0

I have my html setup like this.

<div id="product-module">
   <ul id="product">
      <li><input name="product" type="radio"/></li>
      <li><input name="product" type="radio"/></li>
      <li><input name="product" type="radio"/></li>
   </ul>
   <table id="quantities"/>

   <script id="myTemplate" type="text/x-handlebars-template">
        {{#each this}}
        <tr>
            <td class="quantity">
                <label class="checked" for="quantity_{{id}}">
                    <input type="radio" value="" name="quantity"> 
                    {{quantity}}
                </label>
            </td>
        </tr>
    {{/each}}
   </script>
</div>

I'm trying to setup an event handler that listens for clicks on li and renders the template within the quantities element.

My backbone view

el: '#product-module',

template: Handlebars.compile($("#myTemplate").html()),

events: {
    "click #product li": "liClicked",
},

initialize: function(){
    this.listenTo(this.collection, 'reset', this.render);
},

render: function() {
    console.log('model ' + this.template(this.collection.toJSON()))
    this.$el.html( this.template(this.collection.toJSON()));
},

liClicked: function(event, callback){
    console.log('liClicked')
},

If I change el to #quantities, then my event handlers don't work outside of the el. If i change my el to #product-module, then everything gets replaced. How do I get my event handlers to listen and the template to render within the #quantities element?

I've also tried this with no success

$('#quantities', this.el)

TypeError: $(...) is not a function

Code Junkie
  • 7,602
  • 26
  • 79
  • 141
  • What are you trying to do with `$('#quantities', this.el)` ? If you're trying to insert `this.el` into `#quantities` then you want `$('#quantities').append(this.el);` – Cory Danielson Jun 22 '15 at 19:36
  • I wasn't sure if there was a "backbone" way of handling this. The other solution appears to be using jQuery which required me to have to wrap my js in a jQuery function. – Code Junkie Jun 22 '15 at 19:38
  • `If i change my el to #product-module, then everything gets replaced.` The HTML that is getting replaced should be part of your template. Is there any reason why it can't be? – Cory Danielson Jun 22 '15 at 19:39
  • What does the `#myTemplate` template look like? – Cory Danielson Jun 22 '15 at 19:40
  • I have a list outside of the template that contains radio buttons. I do not want to refresh the radios, I want to refresh the template below. – Code Junkie Jun 22 '15 at 19:41
  • updated the template – Code Junkie Jun 22 '15 at 19:42
  • Backbone doesn't replace the template where it's defined inside of your markup. You use the template to render markup and then can insert it where you want. Normally you would just override what's inside of `this.el`. You're kind of using Backbone incorrectly in that sense, because the root element of the view is already populated with HTML... but you can work around it. I'm working on an answer – Cory Danielson Jun 22 '15 at 19:46
  • If I'm using this in correctly, what would be an appropriate way of doing this without using it in correctly? How could I get my event listeners to listen outside of the el? – Code Junkie Jun 22 '15 at 19:50
  • You wouldn't get event listeners to listen outside of the `el`. Backbone Views are only concerned with their root element and the children of that element. I'm not sure how those radio buttons are getting onto your page, but they should be controlled by another view, or even this view if possible. As far as communicating between views, there's SO questions and blog posts written about it http://stackoverflow.com/questions/7485657/backbone-js-communication-between-views – Cory Danielson Jun 22 '15 at 19:53
  • The first radio group is being inserted with the grails framework on page load. They never change which was the reason I wasn't loading them with backbone. I also worry the views won't be available to search bots since they are javascript loaded. – Code Junkie Jun 22 '15 at 19:56
  • Ah, so you could set the `el` to `#product-module` and then inside of `render` have the view render the template to `#quantities` – Cory Danielson Jun 22 '15 at 19:58
  • Yes exactly what I was thinking. I'm just not sure if it's a backbone hack. – Code Junkie Jun 22 '15 at 20:00

2 Answers2

1

HTML

<script id="myTemplate" type="text/x-handlebars-template">
    {{#each this}}
    <tr>
        <td class="quantity">
            <label class="checked" for="quantity_{{id}}">
                <input type="radio" value="" name="quantity"> 
                {{quantity}}
            </label>
        </td>
    </tr>
    {{/each}}
</script>

<div id="product-module">
   <ul id="product">
      <li><input name="product" type="radio"/></li>
      <li><input name="product" type="radio"/></li>
      <li><input name="product" type="radio"/></li>
   </ul>
   <table id="quantities"/>
</div>

View

el: '#product-module',

template: Handlebars.compile($("#myTemplate").html()),

events: {
    "click #product li": "liClicked",
},

initialize: function(){
    this.listenTo(this.collection, 'reset', this.render);
},

render: function() {
    var markup = this.template(this.collection.toJSON());
    // this.$() is short for this.$el.find()
    this.$('#quantities').html(markup);
},

liClicked: function(event, callback){
    console.log('liClicked')
},
Cory Danielson
  • 14,314
  • 3
  • 44
  • 51
  • 1
    ["If jQuery is included on the page, each view has a **$** function that runs queries scoped within the view's element. ... It's equivalent to running: `view.$el.find(selector)`](http://backbonejs.org/#View-dollar) – mu is too short Jun 22 '15 at 20:08
  • Yeah, I just prefer to use `this.$el.find` rather than the the shorthand which might require extra explanation. – Cory Danielson Jun 22 '15 at 20:29
  • 1
    @CoryDanielson I was just going through a huge tutorial and I actually stumbled along a better way to handle this. this.$el.find('#quantities') is the equivalent to this.$('#quantities'). You should probably update your answer with that no code as it appears to be a cleaner solution. You can find the reference at the very end of this video around 2:50 https://www.youtube.com/watch?v=IOedHUl6-MQ – Code Junkie Jun 23 '15 at 18:49
  • Updated~ I like to use `this.$el.find` on stackoverflow, because it's more obvious for people who are new to Backbone. – Cory Danielson Jun 23 '15 at 19:59
0

Solution was to wrap my backbone js with a jquery function

$(function () {

})

and use the following code

$('#quantities', this.el).html( this.template(this.collection.toJSON()));
Code Junkie
  • 7,602
  • 26
  • 79
  • 141