Search code examples
javascriptdojoaspectgridx

Reference to "this" lost when using dojo aspect around a GridX tree


I am trying to use an around aspect for the expand function of a GridX's tree.

The simplified code goes like:

var myGrid = ...; // features a tree
var myConditional = ...; // some boolean


dojo.aspect.around(myGrid.tree, "expand", function(original) {
    return function(id, skip) {
        // TODO check the conditional and decide whether 
        // to return the deferred function as is, or 
        // return a function that does nothing but log into the console
        var deferred = original(id, skip);
        return deferred;
    };
});

Unfortunately, the invocation of dojo aspect as is (i.e. without any check for my conditional, etc.) is problematic.

Once the expando is clicked, an error is thrown in the console:

Uncaught TypeError: t.isExpanded is not a function

... pointing at the body of the GridX tree module's expand original function:

var d = new Deferred(), t = this;
if(!t.isExpanded(id) && t.canExpand(id)){ // here

Clearly my interpretation of how aspect around works is mistaken, and the scope of t becomes the Window object instead of the tree itself.

I am hoping there's a quick fix/workaround I can use?

Clarification on my actual purpose

Under certain circumstances, the back-end queried by the store underlying the grid will be unreachable for a short amount of time. The way things are implemented, expanding on nodes of the tree will query the back-end. During the very short window while the back-end is unavailable (which I can easily know from the front-end code), I'd like to ignore clicks on the expandos).


Solution

  • Try to bind tree instance to your function. Something like this:

    var myGrid = ...; // features a tree
    var myConditional = ...; // some boolean
    
    const condExpand = function(id, skip) {
            var deferred = original(id, skip);
            return deferred;
        }.bind(myGrid )
    
    
    dojo.aspect.around(myGrid.tree, "expand", function(original) {
        return condExpand
    });
    

    I'm not sure about where a particular context is lost in your case, but you can play with this to make it work for you.

    Update:

    Tried to reproduce situation. Below is working example:

        const testObject = {    
          isNumeric: function(number) {
            return typeof number === "number"
          },
          testMethod: function() {
            console.log('testMethod', this)
            console.log("Is 5 a number: ", this.isNumeric(5))
          }
        }
    
        const aroundFunc = function(originalTestmethod){
            return function(method, args){
              // doing something before the original call
              console.log("Before", this)
    
              //Here context still corect. 
              //So bind it to passed here original method:
    
              var deferred = originalTestmethod.bind(this)(method, args)
    
    
              // doing something after the original call
              console.log("After")
              return deferred;
    
            }
          }
    
    require(['dojo/aspect'], function(aspect) {
       aspect.around(testObject, "testMethod", aroundFunc)  
       testObject.testMethod()  
    
    })
    

    JS Fiddle