Reputation: 549
I have a question regarding aurelia. Let's say I have a product class, and this product has tags. A concrete example: A shirt is a product, and it has some tags users can query on such as Men, XL, blue etc. Their JSON representation is like
{
"id": 3,
"name": "Shirt",
"sku": "WCZR-1",
"tags": [
{
"id": 1,
"name": "XL"
},
{
"id": 2,
"name": "Blue"
}
]
}
If an administrator is looking at the detail view of this product and can edit tags, s\he will be looking at a view as follows:
<div class="form-group">
<label>SKU</label>
<input type="text" value.bind="item.sku">
</div>
<div class="form-group">
<label>Tags</label>
<tag-manager item.bind="item"></tag-manager>
</div>
Notice that I have another custom element called <tag-manager>
, which is a child element of the product detail element. As you may have guessed, it exposes a bindable object in its export: @bindable item = null;
This way, the parent element passes in the product to the child element, where the administrator can add\remove tags by using this tag-manager. For the administrator to be able to edit tags, s\he needs to click the edit button.
This puts the item in the Edit Mode. The parent element (the product details element), does that by adding a InEditMode
property to the product when the user clicks the edit button.
enterEditMode(){
this.item.inEditMode = true;
this.savedItem = JSON.parse(JSON.stringify( this.item ));
}
Note that the inEditMode property does not come from the web api, it is dynamically added.
Now, this mostly works, when the product is in the edit mode, the child element (tag-manager) can add\remove tags from the product, and both parent and child see that product tag collection is modified. Sample code from tag manager:
removeTag(tag){
this.item.tags = this.item.tags.filter(function(el){
return el.id !==tag.id;
})
}
addTag(tag){
this.item.tags.push(tag);
}
these functions work and modify the item's tag collection successfully, one thing that is not working is the product.InEditMode property. When the parent element (the detail view puts the product in the edit mode, the tag-manager recognizes this only for the view activation. But clicking edit | cancel at the parent after initial load and changing the inEditMode property in the parent is not reflected in the child view afterwards. So although the tag property of the product is being observed, the inEditMode property is not being observed by the child. If I import the observer locator in aurelia and watch the property, it does not make a difference. Sample code:
import {ObserverLocator} from 'aurelia-framework';
var subscription = this.observerLocator
.getObserver(this.product, 'inEditMode')
.subscribe(this.onChange);
}
onChange(newValue, oldValue) {
//this method is called only once at the activation of the child,
//no clicks in the parent can trigger this method again
}
As seen in the comments, the onChange
method is called only once on activation; after activation, no clicks on the parent (edit, cancel edit) will be reflected in the child element and onChange won't be called again.
I was able to get this working by using eventAggregator
but I really would like to know why I cannot observe a bool property of an object from the parent.I don't want to abuse eventAggregator
without understanding what's going on behind the scenes. Any clues will be appreciated!
Edit:
The plunker for this problem is at
http://plnkr.co/edit/0gMZFhtKA2r6nec9kGUC?p=preview.
Slightly different issue than what I am seeing but the child view still does not reflect changes at the parent viewmodel.
Upvotes: 3
Views: 1240
Reputation: 8047
I would recommend a slightly different approach, using BindingEngine
:
@bindable product;
productChanged(newValue, oldValue) {
if (this.inEditModeSubscription) {
this.inEditModeSubscription.dispose();
this.inEditModeSubscription = null;
}
if (newValue) {
this.inEditModeSubscription = this.bindingEngine
.propertyObserver(newValue, "inEditMode")
.subscribe(this.onEditModeChanged);
}
}
inEditModeSubscription = null;
Adding the property-observer for product.inEditMode
from within productChanged
makes sure you don't accidentally add the observer to a null
or undefined
object, and it will refresh the subscription whenever your product
is set to a different object.
This ensures that your onEditModeChanged
is always fired when the property changes.
Upvotes: 0