cancel
Showing results forΒ 
Search instead forΒ 
Did you mean:Β 

binding context is undefined

Former Member
0 Kudos

Hi all.

I am trying to learn some of the binding concepts of SAPUI5 but I am stuck on a point in which I hope you all can help me out πŸ™‚

I am building an application which shows an input screen, on this screen a user can enter a material number and with value suggestions they can select the correct one after which a form gets shown underneath the input field with all properties of the chosen material item. A lock icon in the footer indicates if this material number is currently locked and if it is you can unlock it if it is not locked you can lock it. Locking an material number simply updates the 'OBSOLETE' field into an 'X' and unlocking updates this same field into an '-'.

So what happens when a user selects an material from the input field is the following code:

oView.bindElement({

            path: this._oPath,

            parameters: {

              expand: 'industry,category'

            },

            events: {

              dataReceived : this.toggleButtons()

            }

          });


this.toggleButtons()


As you can see I already tried to use the dataReceived event and it also shows where my problem lies. This binding succeeds, the item gets shown on the screen but I want the "lock" button on the footer to automatically show the right icon for the current state. This I do by executing a function named "this.toggleButtons();" First I tried executing it after the bindElement call, then I tried to execute it through the "dataReceived" event of the binding itself.

This function simply executes the following function:

      var oView, oItem;

      oView = this.getView();

     oItem = oView.getBindingContext();

      // // set the buttons correct based on the status

     if (oItem.getProperty("OBSOLETE") === 'X') {

        oView.byId("obsolete").setIcon("sap-icon://locked");

      } else {

        oView.byId("obsolete").setIcon("sap-icon://unlocked");

     }

The problem is that "oItem" is undefined. I think that this has to do with the asynchronous way of working (the binding simply isn't finished yet when the function gets called) but if that is the case, should that not be solved by the "dataReceived" event then? Because even through this "dataReceived" event oItem is still undefined? I even tried to put an "alert" in the "this.toggleButtons" function an I noticed that only after closing the alert box my data gets shown on the form (binded)... while I would expect that the dataReceived function would first bind the data on the form and then call the function (which means I should see the data already when the alert box pops up).

So clearly I am not fully understanding this way of working yet but is there anyone who understands what I am doing wrong and know how I could solve my issue? I just want to get access to the bindingContext of the view from the this.toggleButtons function.

Kind Regards,

Nico

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

Just some additional information, I just noticed that the problem seems to be related to the "expand" option:

  parameters: {

              expand: 'industry,category'

            },

When I remove this everything works fine, ofcourse I understand that this indeed takes more time since it needs to look up these values from other tables first but still.. shouldn't the "dataReceived" event take care of this and only execute the function when all data is retrieved?

jibin_joy
Contributor
0 Kudos

Hi N Van der Linden ,

  The Above code calling a function instead of Registering  the Function !!!

oView.bindElement({

            path: this._oPath,

            parameters: {

              expand: 'industry,category'

            },

            events: {

              dataReceived : this.toggleButtons <---- Remove ()

            }

          });


Error is coming because Function is called before Element is Binded and Once code is changed as mentioned please ensure "this" will be pointing to Event Object not Controller Object by default !!!

For More Information :

JsDoc Report - SAP UI development Toolkit for HTML5 - API Reference - sap.ui.model.Binding

Regards,

Jibin Joy

Former Member
0 Kudos

Hi Jibin Joy,

thanks for your answer, that was really helpful πŸ™‚

I removed the '()'  so my event is now dataReceived: this.toggleButtons. This works very good but indeed, the "this" variable now points to the event object and not the controller anymore (as expected).

However, is it still possible to get access to the controller from within the called function? e.g. can I send parameters to the function which is called? Normally I would use this.toggleButtons(this.getView().sId) for example but can you still do something like that when we register a function? Or is there another way to access the controller after calling the function?

Former Member
0 Kudos

Hi Jibin Joy,

I am a little bit further, instead of registering a named function i tried a anonymous callback function. So I changed the code to:

events: {

     dataReceived: function() {

     alert("test");

     oView.byId("obsolete").setEnabled(true);

     if (oView.getBindingContext().getProperty("OBSOLETE") === 'X') {

       oView.byId("obsolete").setIcon("sap-icon://unlocked");

       oView.byId("obsolete").setTooltip("{i18N>markAsActive}");

     } else {

       oView.byId("obsolete").setIcon("sap-icon://locked");

       oView.byId("obsolete").setTooltip("{i18N>markAsObsolete}");

     }

}

and indeed this works, now I have access to all the variables (e.g. oView which points to this.getView()) which were included in the parent function. But does this mean that this is the way to do it or is there also a way to call a function and provide values to it?

In the API guide to which you also linked I see that the definition is "attachDataReceived(fnFunction, oListener?)" while the one of the onPress event (on which I know you can send values) is "attachPress(oData?, fnFunction, oListener?)" So from that point of view it seems that sending values is not possible?

Kind Regards,

Nico van der Linden

jibin_joy
Contributor
0 Kudos

Hi N Van der Linden ,


  1. Yes this is possible ..


events: {

     dataReceived: function() {

     alert("test");

     oView.byId("obsolete").setEnabled(true);

     if (oView.getBindingContext().getProperty("OBSOLETE") === 'X') {

       oView.byId("obsolete").setIcon("sap-icon://unlocked");

       oView.byId("obsolete").setTooltip("{i18N>markAsActive}");

     } else {

       oView.byId("obsolete").setIcon("sap-icon://locked");

       oView.byId("obsolete").setTooltip("{i18N>markAsObsolete}");

     }

}


Just for Information  :  This is called JavaScript Closures




2. We can Use "attachDataReceived(fnFunction, oListener?)" also .

- fnFunction : Event Handler

- oListener : In Short if I explain , If we pass any parameter as oListener then in function passed object will be "this" Pointer .


For Example : attachDataReceived(this.toggleButtons , this.getView());


then in function toggleButtons  "this" will be point to view object.


Regards,

Jibin Joy



Former Member
0 Kudos

Great thanks for this explanation, the pieces of the puzzle are finally falling on its place πŸ™‚

I do have one last question though, you mentioned to use:

attachDataReceived(this.toggleButtons , this.getView());


But how should I translate this code in the bindElement 'events' part of my code? I know have:


oView.bindElement({

            path: this._oPath,

            parameters: { expand: 'industry,category' },

            events: {

               dataReceived: (this.toggleButtons,this) <-- I tried this.getView() and oView as well

            }

});

But when I try to execute it I get the error "TypeError: Cannot read property 'call' of undefined"


Do you have any idea what I am doing wrong in the call? e.g. "dataReceived: (this.toggleButtons)" runs fine but then the "this" variable is pointing to the event object again of course...

jibin_joy
Contributor
0 Kudos

Hi N. van der Linden ,

There is small Limitation here !!! 

1.  while Bind Element we cannt pass Listener 

oView.bindElement({

            path: this._oPath,

            parameters: { expand: 'industry,category' }

});

oView.getElementBinding().attachDataReceived(this.toggleButtons , this.getView());



2. Using Jquery Proxy


oView.bindElement({

            path: this._oPath,

            parameters: { expand: 'industry,category' },

            events: {

               dataReceived: jQuery.proxy(this.toggleButtons,this)

            }

});



Regards,

Jibin Joy





Former Member
0 Kudos

Cool thank you very much!

jibin_joy
Contributor
0 Kudos

Just For Information :

  I forget there is one more way for  Passing Listener  (Dont know whether it works for binding Context Events  )

oView.bindElement({

            path: this._oPath,

            parameters: { expand: 'industry,category' },

            events: {

               dataReceived: [this.toggleButtons,this]

            }

});

Regards,

Jibin Joy

Answers (0)