Playing with Ember.Object.reopen(), why I have those results? - ember.js

I was trying to answer this question: emberjs: add routes after app initialize()
I started to play with Ember.Object.reopen(), to understand how it works, and perhaps finding a way of answering the previous question.
I feel a bit puzzled, and don't understand the behavior of this code:
jsfiddle: http://jsfiddle.net/Sly7/FpJwT/
<script type="text/x-handlebars">
<div>{{App.myObj.value}}</div>
<div>{{App.myObj2.value}}</div>
<div>{{App.myObj3.value}}</div>
</script>
App = Em.Application.create({});
App.MyObject = Em.Object.extend({value: 'initial'});
App.set('myObj', App.MyObject.create());
Em.run.later(function(){
App.get('myObj').reopen({
value: "reopenOnInstance"
}); // the template is not updated, 'initial' is still diplayed, but
console.log(App.get('myObj').get('value')); // print 'reopenOnInstance'
App.MyObject.reopen({
value: "reopenOnClass"
});
App.set('myObj2',App.MyObject.create()); // the template is updated and
console.log(App.get('myObj2').get('value')); //print 'reopenOnClass'
App.myObj3 = App.MyObject.create(); // the template is not updated but
console.log(App.myObj3.get('value')); // print 'reopenOnClass'
Em.run.later(function(){
App.get('myObj').set('value', "setWithSetter"); // the template is updated and
console.log(App.get('myObj').get('value')); // print 'setWithSetter'
App.get('myObj2').set('value', "setWithSetter"); // the template is updated and
console.log(App.get('myObj2').get('value')); // print 'setWithSetter'
App.myObj3.set('value', "setWithSetter"); // the template is not updated but
console.log(App.myObj3.get('value')); // print 'setWithSetter'
}, 2000);
},2000);
If someone can explain what is going on, particularly why the templates are sometimes not updated, sometimes updated, and also what's the difference between calling reopen on a class, calling it and on a instance.

Not 100% sure, but I will try and answer you questions.
First lets look at "myObj3". The ember getter/setter methods trigger the updates in the templates (they fire internal events which cause every property/observer to know something happened). Just setting a value by hand does update the value but will not fire these events and hence nothing changes in the UI. Kind of like when you use a Mutable list you use pushObject to make sure the UI updates.
Now lets look at your "reopen". When you reopen on the class it works as you would expect and updates the base class. When you reopen an instance it is actually creating a mixin and shims it on top of the object. This means when you do a "get" ember iterates over the mixin & object for the value to return. It finds that mixin and gets the value before the object; you could actually replace the method with a "return 'foo '+this._super()" on the instance you will get 'foo initial' (think of your object has having layers like an onion). If you have a group of mixin on top of your object you will have a hard time finding the correct value if you set something directly (but "get" will work perfectly). This leads to the general rule that you should always use "set" instead of a direct reference.
Side note: You can call "getPath" instead of "get" and you can use the relative or absolute path. Such as App.getPath('myObj2.value') which will make the code a little easier to manage. Goes for "setPath" also.
Lastly: The last value prints because you did change the value (it is in there) but the trigger for ember to update the ui never fired because you never called set on "myObj3" object.
EDIT: In the lastest version of ember it looks like the reopen on an instance does do a merge-down on the object (if that key already exists). The mixin only will wrap if you are adding new content.

Related

Update an element that already has a plugin

Zurb Foundation 6.5.3
I have an accordion menu which needs to be updated via ajax after the initial page load. So initially the menu contains 2 items, then $(document).foundation(); is called. Later after an ajax response is received elements are added (and potentially removed/replaced) within the menu.
I would like to be able to re-use the same elements however, I can't update the plugin to re-style the changed elements. I've tried:
$("#my-menu").foundation(); which doesn't work and shows the error:
Tried to initialize accordion-menu on an element that already has a Foundation plugin.
Foundation.reflow(menu, 'accordion'); which doesn't work.
menu.foundation('reflow'); which doesn't work and shows the error:
Uncaught ReferenceError: We're sorry, 'reflow' is not an available method for AccordionMenu.
I have made it work by destroying and removing the existing menu, re-creating the whole thing, then calling $("#my-menu").foundation(); however this isn't ideal in my opinion.
I found that my issue was due to no one solution working in all 3 cases:
foundation has not yet been initialised
foundation is initialised and the entire element has been replaced since
foundation is initialised and the element has been updated since
Unless someone has a better answer, I solved using this approach:
// this can happen before, or after code creates the menu
$(document).foundation();
console.log("foundation run");
__foundationRun = true;
...
function foundationUpdate(el) {
if (__foundationRun) {
if (el.data('zfPlugin'))
// already initialised, update it
Foundation.reInit(el);
else
// new element, initialise it
el.foundation();
}
// else leave for foundation initialise
}
....
// ... do updates (modify or replace entirely) and then:
foundationUpdate($("#my-menu"));

Ember ember-views.render-double-modify

Using Ember.2.1.0-beta4
I am getting the "ember-views.render-double-modify" in a function triggered by the "didReceiveAttrs" of a subcomponent.
I tracked down the statement this.set('_columns', columns) that triggers the error. However, AFAIK this is the first time the attribute is modified.
To debug it, I created an observer for the modified attribute, and put a breakpoint there. However, the observer is only called once and the error is still there, so it looks like this is the first call.
How should I debug this -- is this an Ember bug, or are there other restrictions on setting attributes that aren't clear in the error? Note that the attribute is used in the component's template. Also the attribute is used in other computed attributes (e.g. _columns.#each.width and _columns.[]).
For posterity's sake, the answer in my case was: _columns is used in the template. Thus, for didReceiveAttrs of the subcomponent to be called, the previous value of _columns was already used.
The error message is a little misleading, but the idea, I think, is that once you start to render you can't change properties until you are done. If necessary, use Ember.run.scheduleOnce('afterRender', ...).

"Cannot call method 'destroy' of undefined" in arrayWillChange

I have what I think is a pretty standard array/template relationship setup, but when I push a new item into the array I get the above mentioned Cannot call method 'destroy' of undefined error in the arrayWillChange method of the Ember source:
for (idx = start + removedCount - 1; idx >= start; idx--) {
childView = childViews[idx];
if (removingAll) { childView.removedFromDOM = true; }
childView.destroy(); <-- childView is undefined
}
I have never had this issue before. This doesn't happen when I remove an item from the array. Only on addition. Below is a link for a JSBin where I tried to duplicate the issue. The error doesn't get thrown but the template doesn't update either.
http://jsbin.com/asemul/2
EDIT:
You're calling array.push instead of array.pushObject -- the latter is an Ember.js method that is binding aware, which means it will automatically update bindings for you. The handlebars template helper {{#each filters}} is a binding to the filters array of the controller, and the template needs to know to update when the underlying array is updated. push doesn't tell the binding to update, but pushObject does.
Here's a working example (all I did was change push to pushObject): http://jsbin.com/asemul/6/
This is a pretty common mistake -- usually, I find that if my templates aren't synchronized with the underlying object, it's because something's wrong with the bindings, so that's where I start looking.
END EDIT
I don't think you should be setting removedFromDOM directly -- try using childView.remove() followed by destroy().
I'm not sure what the context is, but have you looked at ContainerView or CollectionView? Both of those views have support for arrays of child views and may accomplish what you're looking to do both more robustly and with less code.

What is valPtr in ctor of wxTextValidator good for?

I'm using a simple numeric text validator wxTextValidator along with a wxTextControl. I wonder what the 2nd parameter is good for:
wxTextValidator(long style = wxFILTER_NONE, wxString* valPtr = NULL)
I simply passed the reference to a member variable:
myTextControl_->SetValidator( wxTextValidator(wxFILTER_NUMERIC, &myValue_) );
I'm using wxWidgets 2.8.12, from the documentation I figured that the myValue_ variable would receive the validated content of the text control, but this does not happen in my application.
Am I doing something wrong or does the valPtr parameter not receive the content of the text control?
The myvalue_ variable should receive the value entered if you call wxValidator::Validate or wxValidator::TransferFromWindow. This happens automatically if you close the dialog with the default OnOK() handler. Otherwise you have to do it yourself.
Ravenspoint has already answered the initial question but I'd just like to add that wxValidator can be used either for validating or for data transfer -- or for both at once. In fact, some validators, such as wxGenericValidator are only used for data transfer (it doesn't make much sense to validate a check box or a radio button!). So the name of this class is somewhat misleading as it describes at most half, and probably less than that, of its uses.

getElementsByTagName returns 0-length list when called from didFinishLoad delegate

I'm using the Chromium port of WebKit on Windows and I'm trying to retrieve a list of all of the images in my document. I figured the best way to do this was to implement WebKit::WebFrameClient::didFinishLoading like so:
WebNodeList list = document->getElementsByTagName(L"img");
for (size_t i = 0; i < list.length(); ++i) {
// Manipulate images here...
}
However, when this delegate fires, list.length() returns 0. The only times I've seen it return a list of non-zero length is when I substitute "body" or "head" for "img". Strangely enough, if I call getElementsByTagName(L"img") outside of the delegate, it works correctly.
I'm guessing that the DOM isn't fully loaded when didFinishLoading is called, but that would seem to contradict the delegate's name. Does anyone know what I may be missing here?
It turns out that the mistake was purely on my side. I was caching a pointer to the DOM document in my frame wrapper. Of course, since a frame can outlive a DOM document, I ended up referencing an out-of-date document once I loaded a new page.