Gleeb
Gleeb

Reputation: 11289

Backbone.js fails to load Tinymce script only when moving through the router

I am using tinymce to create a rich Textarea, and I am using backbone.js.

The problem is that when i move to that "page" in my router from a previous URL that is on the same site, it just doesn't work.

If i refresh the page with the direct link to that route it works fine. I really don't understand what can go wrong.

Here is the view:

var template = function (name) {
    var source = $('#' + name + '-template').html();
    return Handlebars.compile(source);
}; 
  BT.Common.FormTextArea = Backbone.View.extend({
    template : template('form-input-textarea'),
    tagName: 'div',
    className: "control-group",
    initialize: function(){
    },
    render: function(){
        console.debug("Render FormTextArea");
        var html = this.template(this.model.toJSON());
        this.$el.html(html);    
        tinymce.init({selector:'textarea'});
        return this;
    },
});

The template:

  <script type="text/x-handlebars-template" id="form-input-textarea-template">
      <label class="control-label" for="message">{{lable}}</label>
      <div class="controls">
        <textarea name="msgpost" id="msgpost" cols="50" rows="10">
            {{text}}  
        </textarea>
      </div>
</script>

Upvotes: 3

Views: 994

Answers (3)

SimDion
SimDion

Reputation: 1080

When rendering (Backbone.View.render), the el isn't inserted in the dom yet. Also, it is impossible to catch the moment when the view's el will be inserted in the dom. But a thing that is sure, is that at the end of the current browser's process, the el will be inserted in the DOM. Then tinyMCE will be "initializable". Simply wait 1 millisecond using "setTimeout" :

var FormTextArea = Backbone.View.extend({
    template : _.template('<%=value%>'),
    tagName: 'textarea',
    className: "control-group",
    render: function(){ 
        this.$el.html(this.template(this.model.toJSON()));
        setTimeout(_.bind(this.initMCE, this), 1);
        return this;
    },
    initMCE: function(){
        tinymce.init({selector: 'textarea'});
    }
});

var v = new FormTextArea({
    model: new Backbone.Model({value: '<h2>Heading 2</h2><p>A paragraph here</p>'})
});

$('body').append(v.render().el);

The jsfiddle :

http://jsfiddle.net/pCdSy/10/

Upvotes: 0

Gleeb
Gleeb

Reputation: 11289

I Solved it by creating an Iframe view and bringing small html code for the text area.

BT.Common.IframeTextArea = Backbone.View.extend({
    tagName: "div",
    className: "row",
    template : template('form-input-textarea'),
    render: function(){
        var html = this.template();
        this.$el.html(html);
        return this;
    }
});

and the template is just:

<script type="text/x-handlebars-template" id="form-input-textarea-template">
    <div class="span12">
      <iframe src="resources/textArea.html" style="width:100%;height:600px;border:0;padding:0"></iframe>
    </div>
</script>

and the textArea.html is:

<script src="js-frameworks/tinymce/tinymce.min.js"></script>
<script type="text/javascript">
tinymce.init({
selector: "textarea",
plugins: [
    "advlist autolink lists link image charmap print preview anchor",
    "searchreplace visualblocks code fullscreen",
    "insertdatetime media table contextmenu paste"
],
toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright
     alignjustify | bullist numlist outdent indent | link image"});
  </script>
  <textarea name="content" style="width:100%"></textarea>

Upvotes: 0

nikoshr
nikoshr

Reputation: 33364

TinyMCE apparently doesn't like to work on detached nodes. At all.

This setup reproduces your predicament:

var v = new BT.Common.FormTextArea({
    model: new Backbone.Model({text: 'init'})
});

v.render().$el.appendTo('body');

and an accompanying Fiddle http://jsfiddle.net/nikoshr/pCdSy/

A simple workaround would be to provide your view an attached node. For example, assuming #render is in the DOM:

var v = new BT.Common.FormTextArea({
    model: new Backbone.Model({text: 'init'}),
    el: '#render'
});

v.render();

and an updated Fiddle http://jsfiddle.net/nikoshr/pCdSy/2/

Another solution would be to temporarily add your view el to the DOM, apply TinyMCE and then detach it.

var BT.Common.FormTextArea = Backbone.View.extend({
    template : template('form-input-textarea'),
    tagName: 'div',
    className: "control-group",

    initialize: function(){
    },

    render: function(){
        console.debug("Render FormTextArea");

        var html = this.template(this.model.toJSON());
        this.$el.html(html);    

        $('body').append(this.$el);   
        tinymce.init({selector: 'textarea'});
        this.$el.detach();

        return this;
    }
});

http://jsfiddle.net/nikoshr/pCdSy/4/ for a demo

Warning : this really looks like a hack and might produce unexpected results.

Upvotes: 2

Related Questions