sub-function call of ready function gets a different 'this' value. All globels are undefined

50 views
Skip to first unread message

Just.A.Guy

unread,
Feb 25, 2014, 8:57:39 PM2/25/14
to polym...@googlegroups.com
I just wrote a "ready" routine for a custom element.
When the "ready" routine is called, "this.shadowRoot" points to the shadowRoot 
and the routine can access the global (polymer-element attributes) values.

At the end of the "ready" routine a call is made to a routine that appears above ready-routine.
In that routine it tries to access the global values.  In the debugger they are all undefined.
From what I can tell, the "this" points to new window that does not have any of the variables
that the ready routine used and created.

I get an error saying you can not call <xxxx> on undefined.
But if I copy the contents from the routine, to just below the call, and comment out the call
everything works correctly. 

The sub-function is part of the elements "script" contents but is not a part of the global options.
I don't want to clutter all of the dependent functions of the element as global functions. This should not be necessary. 


here are some snippets of the code:

---------------------------------------------------------------

       var update_entire_line = function ()
          {
             my_debug('update_entire_line');
             var lrecl = this.lrecl;
             this.lcol.innerHTML  = this.lc_text;
             this.caret.innerHTML = this.cc_text;
             this.rcol.innerHTML  = this.rc_text;
          };

.................... 

          var initialize_listeners = function ()
          {
             my_debug('initialize_listners');


             var my_doc  = this.shadowRoot;
             this._root  = this.shadowRoot;
             var init_text = this.value;

             if ( init_text == null )
             {
                init_text = '';
             }

             this.lcol   =  my_doc.getElementById('left_col');
             this.caret  =  my_doc.getElementById('caret');
             this.rcol   =  my_doc.getElementById('right_col');

             this.caps_lock = false;
             this.shift_key = false;

             this.lc_text = this.lcol.innerHTML;
             this.cc_text = this.caret.innerHTML;
             this.rc_text = init_text;

             this.lc_len = this.lc_text.length
             this.cc_len = this.cc_text.length
             this.rc_len = this.rc_text.length
             console.log('calling initialize_listeners');
             var lrecl = this.lrecl;

             var it_len = init_text.length
             if ( it_len < lrecl )
             {
                var fill_cnt = lrecl - it_len + 1;
                console.log('fill: '+fill_cnt);
                this.rc_text = init_text + Array(fill_cnt).join(" ");
                this.rc_len = lrecl;
             }

    //         update_entire_line();
             this.lcol.innerHTML  = this.lc_text;
             this.caret.innerHTML = this.cc_text;
             this.rcol.innerHTML  = this.rc_text;

             var ln = my_doc.getElementById('entire_line');
             ln.addEventListener('keydown', key_down, false);
             ln.addEventListener('click', mouse_click, false);

          };
------------------------------------------------------------------------------------------


Steve Orvell

unread,
Feb 25, 2014, 9:46:11 PM2/25/14
to Just.A.Guy, polym...@googlegroups.com
When you define a custom element, you supply a prototype object for the element. When any of the element callback functions are called, 'this' always points to the element. If you then call this.methodName from there, 'this' is still the element.

You haven't shown how the functions you wrote are part of a custom element prototype. This is critical info. In particular 'this' in your 'initialize_listeners' may not be the same as 'this' in your 'update_entire_line' method. At the very least you'd need to do update_entire_line.call(this);

For some basic info about constructing raw custom elements, see the 'Adding JS properties and methods' section here: http://www.html5rocks.com/en/tutorials/webcomponents/customelements/.

Here's some background on the 'this' keyword for reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this.





Follow Polymer on Google+: plus.google.com/107187849809354688692
---
You received this message because you are subscribed to the Google Groups "Polymer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to polymer-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/polymer-dev/a977b028-bcd5-492b-9827-e112027725a2%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Just.A.Guy

unread,
Feb 25, 2014, 10:23:37 PM2/25/14
to polym...@googlegroups.com

  doing some step by step debug continue, I found the code that calls the "ready" routine 
  The statement is "this.ready". 

   Then I noticed that the prototype for the function object does not include the shadowRoot, nor the "this" from the call.
   That told me a lot. 
   Then I did some step-by-step in one of the listener routines.   It also received the "this" from the function proto-type definition.

   Therefore, I decided to pass the "this" parameter as part of all functions which I call as sub-functions from one of the polymer callback
   routines.
 
   And just before I add a listener to an object in the "ready" routine I attach a reference to the ready routines "this". That way
   when the listener receives control it will have address to the elements global values.  

   I guess another "more elegant" way to do this is to extend the "function" definition into a "polyFunction" and add the 
   reference to the document fragment to the extended function's prototype so it can be reference without having to pass it as a formal argument. 
   But implementing that is too complicated for me. So I will stick to the dumb way of doing it.

   You really don't want all of those internal functions on the global options list. It reveals too much of the internal structure of the object.
   Because as I understand it,  if a function is on the global options list then a script program can call those functions from
   a reference to the object (i.e. getElementById). 

   

Just.A.Guy

unread,
Feb 25, 2014, 10:27:16 PM2/25/14
to polym...@googlegroups.com
I think I did. You may find the "update_entire_line" call commented out and the three lines in the body of that function
copied under the comment. If you remove the comment to make the call active, and comment out the 3 lines below
it you will be able to recreate the problem. 

Scott Miles

unread,
Feb 25, 2014, 10:36:07 PM2/25/14
to Just.A.Guy, polymer-dev
I'm afraid you are fundamentally misunderstanding the role and usage of `this` in JavaScript. Please review the link Steve provided.

>> If you remove the comment to make the call active, and comment out the 3 lines below it you will be able to recreate the problem

Reading carefully, Steve suggested this alteration:

>> update_entire_line.call(this);

Looking up 'Function.prototype.apply' and 'Function.prototype.call' methods may also be helpful for you.


Follow Polymer on Google+: plus.google.com/107187849809354688692
---
You received this message because you are subscribed to the Google Groups "Polymer" group.
To unsubscribe from this group and stop receiving emails from it, send an email to polymer-dev...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages