Search code examples
javascriptbackbone.jshandlebars.jsmarionette

Marionette document.querySelector('#test') returns null but doing this.$('#test') does not


I have a simple marionette ItemView,

import Marionette from 'backbone.marionette';
import Tabs from '@component/tabs/src/js/views/Tabs';
import template from '../../../templates/partials/one/tabs.hbs'
export default Marionette.ItemView.extend({
  template,

  onRender() {
    console.log(document.querySelector('#tabs-main')); //--> null
    console.log(this.$('#tabs-main')[0]); // gets appropriate dom element
  }
})

Is there a reason why document.querySelector returns null compared to doing this.$, i need to do document.querySelector because the library that I am using uses it internally when i pass in the id/class


Solution

  • Refer to https://marionettejs.com/docs/v3.5.1/viewlifecycle.html#view-creation-lifecycle

    In onRender, the template will be rendered in memory (i.e. this.$el), but not yet attached to the DOM.

    You can use onAttached if the view's HTML needs to be in the DOM.

    Note that DOM lookups are slower than lookups done against the view's el, so unless a lookup needs to occur against the DOM, is generally better to use onRender with this.$() lookups.

    Edit: since you're using ItemView, must be using < v3, here is v2 doc for onAttach: https://marionettejs.com/docs/v2.4.7/marionette.view.html#view-attach--onattach-event

    2nd edit: adding snippet (sorry, took a while to find older marionette dependencies)

    var MyView = Backbone.Marionette.ItemView.extend({
      template: Handlebars.compile('<p id="hello-world">Hello World</p>'),
      onRender: function() {
        console.log('onRender');
        console.log('querySelector', document.querySelector('#hello-world'));
        console.log('querySelector equal null?', document.querySelector('#hello-world') === null);
        console.log('this.$el', this.$('#hello-world')[0]);
      },
      onAttach: function() {
        console.log('onAttach');
        console.log('querySelector', document.querySelector('#hello-world'));
        console.log('querySelector equal null?', document.querySelector('#hello-world') === null);
        console.log('this.$el', this.$('#hello-world')[0]);
      }
    });
    
    // ParentView to mock an application
    var ParentView = Backbone.Marionette.LayoutView.extend({
        el: '.test-container',
        template: Handlebars.compile('<div class="my-region"></div>'),
        regions: {
          myRegion: '.my-region'
        },
        onRender: function() {
          var myView = new MyView();
          this.showChildView('myRegion', myView);
        }
    });
    
    var parentView = new ParentView();
    parentView.render();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.3.1/handlebars.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.4.7/backbone.marionette.js"></script>
    
    <div class="test-container"></div>