Posts Tagged ‘modelChanged’

webOS list modelChanged bug

I ran into a bug with the webOS mojo framework a while ago, which I nailed down thanks to this forum post. Simply put, calling this.controller.modelChanged on a list doesn’t work properly if the user has scrolled down the list. With the dotspott webOS app I notice a gray rectangle popping up, obscuring the last 2 items in the list.

From pacemkr,

Calling this.controller.modelChanged on a list that has been scrolled past renderLimit will blank out the screen and not show the changes. This happens because modelChanged handler in the List widget resets renderOffset to 0. In other words the list widget assumes that the user is at the top of the list when modelChanged event happens. This is a pretty nasty bug.

The solution is to use mojo.setLengthAndInvalidate() instead:

listElement.mojo.setLengthAndInvalidate(this.listModel.items.length);

While Mojo has been superseded by Enyo, this is still a pretty big deal, there’s still lots of Pixi and Pre models out there with webOS 1.4.5.

Changing the model of activity buttons on webOS

This little issue drove me insane: you can’t change the model on an activity button after it’s been activated.

So, first, a little background. webOS/Mojo has widgets and one type of widget is a button. Setting up a button requires attributes (to set type – default or activity button) and a model (to set the label, disable/enable, and associated CSS class). A type of Mojo.Widget.activityButton turns the button into an activity button, which adds a spinner (preloader) to the button when the Mojo.Widget.Button.activate() method is called. The Mojo framework also allows altering the model of any widget and calling the Mojo.Controller.SceneController.modelChanged() method to commit the updates.

Here’s some code to show how all of this pieces together. This code is correct and functions as expected.

function setupSignInButton() { var btnModel = { buttonClass: "affirmative", label : "Sign in", disabled: false } var btnAttributes = { type: Mojo.Widget.activityButton } ctrlr.setupWidget("signin-button", btnAttributes, btnModel); Mojo.Event.listen(ctrlr.get('signin-button'), Mojo.Event.tap, function() { btnModel.disabled = true; btnModel.label = "Signing in..."; ctrlr.modelChanged(btnModel); ctrlr.get('signin-button').activate(); }); }

Note, ctrlr is a reference to the scene controller (Mojo.Controller.SceneController).

When the button is tapped, the spinner is activated, the button is disabled, and the label for the button is changed to “Signing in…”, as shown below.

webOS activity button, signing in

The problem is, if you move the call to activate { ctrlr.get(‘signin-button’).activate(); } above the call to change the model { ctrlr.modelChanged(btnModel); }, the model change does not occur. So you have an activated button without the model change, as shown below.

webOS activity button

Note, deactivating the button and attempting the model change does not work.

Edit: After playing with the code a bit more, turns out there’s no need to call activate(), the activity button is activated automatically when the button is tapped. Also, the issue I mentioned above seems to all stem from the call to activate(). It seems no code after the activate() call is executed (I attempted to show an alert dialog) and very much looks like an issue where the activate() call is blocking.

Edit 2: Hmmm, turns out nothing was being blocked, but an uncaught exception was being thrown. If you call a method for a widget as I was doing above, something like the following is thrown:

TypeError: Object# has no method 'activate'

To call a method, you need to put ‘.mojo’ before the method name, so:

ctrlr.get('signin-button').mojo.activate();