Search code examples
javascriptjquerybackbone.js

append has no effect on a form based on Backbone.js


I retrieved a template Javascript / HTML based on Backbone.js. I would need to add a dynamic dropdown list in a field of the following form:

<script type="text/template" id="compose-view-template">
<form id="email-compose" class="form-email-compose" method="get" action="">
    <div class="form-group">
        <select type="email" id="input-to" placeholder="To" class="input-transparent form-control">
        </select>
    </div>
    <div class="form-group">
        <input type="text" id="input-subject" placeholder="Subject" class="input-transparent form-control"
               value="<%= subject %>">
    </div>
    <div class="form-group">
        <textarea rows="10" class="form-control" id="wysiwyg" placeholder="Message"><%- body %></textarea>
    </div>
    <div class="clearfix">
        <div class="btn-toolbar pull-xs-right">
            <button type="reset" id="compose-discard-button" class="btn btn-gray">Annuler</button>
            <button type="submit" id="compose-send-button" onClick="fillEmailDropDown()" class="btn btn-danger">&nbsp;&nbsp;&nbsp;Envoyer&nbsp;&nbsp;&nbsp;</button>
        </div>
    </div>
</form>

</script>

The Backbone part is the following:

        var ComposeView = Backbone.View.extend({


        template: _.template($('#compose-view-template').html()),

        attributes: {
            id: 'compose-view',
            class: 'compose-view'
        },

        events: {
            "click #compose-save-button, #compose-send-button, #compose-discard-button": 'backToFolders'
        },

        render: function() {
            $('#widget-email-header').html(
                '<h5>Nouvel <span class="fw-semi-bold">Email</span></h5>'
            );
            $('#folder-stats').addClass('hide');
            $('#back-btn').removeClass('hide');
            this.$el.html(this.template(this.model.toJSON()));
            this._initViewComponents();


            return this;
        },

        backToFolders: function(){
            App.showEmailsView();


        },

        _initViewComponents: function(){
            this.$("textarea").wysihtml5({
                html: true,
                customTemplates: bs3Wysihtml5Templates,
                stylesheets: []
            });

        }



    });

The Javascript is the following:

$(document).ready(function() {
      var listItems = '<option selected="selected" value="0">- Select -</option>';
      console.log("Preparing Auto Fill of DropDown list for email adresses");

      for (var i = 0; i < jsonData.Table.length; i++) {
        listItems += "<option value='" + jsonData.Table[i].stateid + "'>" + jsonData.Table[i].statename + "</option>";
      }
      $("#input-to").append(listItems);
});

Unfortunately the .append has no effect on the select form, and the Dropdown remains empty. I also tried to use .html instead of append but same result.

If I'm adding the options manually in the select tag, it works properly but I need to fill it dynamically...

any idea ?


Solution

  • It sounds like the issue is likely that backbone hasn't added the #input-to element to your html before you attempt to append to it. That wouldn't throw any errors, it would just silently fail, then backbone would add the (empty) element after the append attempt.

    You only know it is "safe" to append your content after backbone has added the html, and that happens in your render method:

        render: function() {
            $('#widget-email-header').html(
                '<h5>Nouvel <span class="fw-semi-bold">Email</span></h5>'
            );
            $('#folder-stats').addClass('hide');
            $('#back-btn').removeClass('hide');
            this.$el.html(this.template(this.model.toJSON()));
            // NOW IT IS SAFE TO APPEND CONTENT...
    
            this._initViewComponents();
    
    
            return this;
        },
    

    A solution that will definitely work is to add you code that appends to the element directly in the render method. I'd recommend that if the appended content is very intrinsic to the view.

    If that doesn't seem coherent, then a lot will depend on how your backbone is set up. It's probably safe to append the content after the line that initializes your view:

    var myView = new ComposeView({});
    // NOW APPEND CONTENT
    

    However, that will only be safe if:

    1. Your view is instantly rendered when created, and
    2. The render is synchronous (does not fetch external data or templates first).

    Hope this helps, good luck.