Aurelia #bindable *Changed calls on initialisation - aurelia

I'm finding that when I define a #bindable property, and a propertyChanged handler for it, it sometimes gets called before the custom component's bind() method and sometimes doesn't.
https://gist.run/?id=d7d9e7c7080f581f8e81b888268a2f11
In several places, I'm using these propertyChanged handler on one property to trigger updates to another, in situations where a #computedFrom isn't appropriate, as the second value is a complex calculation that I don't want called multiple times.
For now, I'm having to do the following:
#bindable propOne;
#bindable propTwo;
propOneChanged(newVal) {
propTwo = "something complex " + newVal;
}
bind() {
** propOneChanged(propOne);**
}
Is there any better way to do this (e.g. something in the #bindable decorator) so that I don't need to manually 'prime' the property in the bind()?

Is there any better way to do this (e.g. something in the #bindable decorator) so that I don't need to manually 'prime' the property in the bind()?
No.
If you don't have a bind() method, then Aurelia will call your change handlers during bind(). Unless you've got specific things you need to do (besides priming your bindables), remove the bind() method. Then you don't need to worry about this.
If you do have a bind() method, then that's the correct place for you to invoke your change handlers.
Also, I get the impression you're not entirely sure how bindables work.
Simply put: a #bindable decorator tells the Aurelia framework to wrap that property in a get + set method (this happens when the component is loaded, way before its lifecycle).
The set method invokes the change handler whenever it receives a value that's different from the current value - when you assign a value to a bindable, the change handler is invoked, regardless of whether the component is bound, even if it's not a ViewModel.
So to address your comment:
it sometimes gets called before the custom component's bind() method and sometimes doesn't.
It will be called before the custom component's bind() method if and only if you assign some value to it before the custom component's bind(). For example, in the constructor or in the property initializer.

the xyChanged protoype is xyChanged(newValue, oldValue). To prevent unwanted behaviour i'm always doing
if(oldvalue === null) return;
(which is null directly after bind()). If you use async model-requests its in most cases meaningfull to do a null check in your view
<div if.bind="model.data">...</div>

Related

Struggling With MVVM

I have a class named osmAppBarButton that inherits from AppBarButton (UWP) to which I have added a dependency property named ButtonState. (Enum Normal, Dim, Bright, Flash)
I have a Style used on all my osmAppBarButtons, that uses a DataTriggerBehavior to check the ButtonState and select the appropriate VisualState.
I was rather please with myself, as DPs and the VisualStateManager are all new to me. Then I hit a problem..
How can I change an osmAppBarButton's ButtonState from the ViewModel without breaking MVVM ? I thought about having a VM property for the ButtonState of each button in my view, but that would imply that the VM would have some knowledge of the View.
I think that the answer may lie with Attached Behaviours, but I haven't found an example that suits.
Any ideas ?
The way you get values from a viewmodel property to a dependency property is to use a Binding. Certainly not an attached behavior; I'm sure you could find some way to do that with an attached behavior, but just use a Binding.
`The viewmodel must implement INotifyPropertyChanged, and it must be the DataContext for the view where the appbar button lives, and you must not be shooting yourself in the foot by binding DataContext to something random in some parent of the appbar button.
Give the viewmodel a public property that raises PropertyChanged when its value changes. Bind to that property.
An enum like ButtonState with Normal, Dim, Bright, Flash values isn't the kind of thing a viewmodel should be aware of in a "proper" MVVM implementation. This isn't actually a silly point, either. I would suggest having the viewmodel expose its state through properties that express the viewmodel's state in its own terms (I could give you an example, if I knew what you were doing here). Maybe the viewmodel has a State that can be Normal, Busy, Error, Waiting -- those might map onto various ButtonState values. "Error" is a state of the viewmodel. "Flash" is one of many ways a view might choose to communicate a given viewmodel state to the user.
If the viewmodel expresses the relevant state using one or more properties with types other than ButtonState, you'd write a converter -- maybe a multiconverter -- to translate all that into a ButtonState value.
But it won't be the end of the world if your learning program uses ButtonState in a viewmodel, and that'll be simpler. So bind it to this:
private ButtonState _fooBarButtonState = ButtonState.ItsComplicated;
public ButtonState FooBarButtonState {
get { return _fooBarButtonState; }
set {
if (value != _fooBarButtonState) {
_fooBarButtonState = value;
OnPropertyChanged(nameof(FooBarButtonState));
}
}
}
XAML:
<local:osmAppBarButton
ButtonState="{Binding FooBarButtonState}"
/>
But if you'd like to go with my suggestion to use a different state enum in the viewmodel, converters are quite trivial to write. Let me know if you hit a snag, but if you got a dependency property and viewstates working, you'll get it.

onPropertyChanged - How to switch propertyId from external class

I have a model that extends BaseObservable. I have a view model that contains a reference to the model and subscribes to property changes within the model. How do I switch on the Model.propertyId from within the callback in the view model? In the sample below BR.assignedId is the property in the model. For example:
View Model
public void onPropertyChanged(Observable sender, int propertyId)
{
switch (propertyId)
{
case MyModel.BR.assignedId://compile error
notifyPropertyChanged(BR.assignedImage);
break;
}
}
I suggest you to read Observer pattern. The code above has Entities : Observer and Observable. Observer has an Observing method. Any class which wants to observe the 'Observable' needs to register itself as 'Observer'. Observable calls the observing method on the Observer and this is how the usual call back works. (names of classes and methods may be differnt , I used as per the intent and context)
Check 'ViewModel.java' class would be implementing some 'observer' interface which would be having the method 'onPropertyChanged ()'. you will have to set the object of ViewModel.java in Model.java. (check you should be having a method with a name like addPropertyChangeObserver (), though it may be differnt but similar method. Use this method to set the object of ViewModel.java in Model.java. Now Model.java would call the method 'onPropertyChanged' on ViewModel.java.
if you wish to modify something on the Model then check the sender parameter. You can add another method in the interface implemented by Model and can do modifications on Model using it or can simply typecast the sender after checking its type with instanceof and can perform the process on Model.java from the callback method.

OO Design Issue related to subclassing

I have a parent bean having one instance variable like below :
public Class ParentBean {
protected boolean show; // this variable will be used to show some UI component
public void action() {
// update show variable here
}
public boolean isShow() {
return show;
}
}
Is it a good design if I want to reuse the "show" variable in a child bean (to show other UI component specific to child bean ) as shown below :
public Class ChildBean extends ParentBean {
// override the action method from parent bean
public void action() {
// update show variable here
show = true /false;
}
}
In effect , show variable is being updated by "childBean" by overriding action() method.
Is this a good design practice ? Otherwise same thing has to be repeated in ChildBean to get this work done.
If you use the show variable for the same purpose in the subclass, as you seem to be doing in this example, then obviously you should reuse it, because otherwise you just end up writing the same code twice, which is contrary to the point of OOP.
In general, in OOP, it is common to override superclass methods in subclasses, as well as modifying superclass instance variables, as long as you know what the variable you are modifying is being used for (you don't want to be randomly changing instance variables in classes that you don't completely understand, or don't have access to the source of, because you don't want any unfortunate side effects), so when it's your own code, this is absolutely fine.
As a general guideline, if your options are either to copy and paste a massive hunk of code and use it unchanged, or subclass and use the superclass' instance variables or functions, it's better to subclass. Otherwise, you're missing out on the point of OOP.
Changing the value in subclass will not affect superclass variable
This is fine with respect to the design. When a subclass object is instantiated, it will have a different copy of variable. and If superclass object is instantiated it will have different copy.
It is. Having a protected variable means you are allowed to modify it into parent or children classes (remember every single instance of each class has its own property values). So, if you have some generic functionality which is valuable for all the children:
Parent class:
public void action(){
//update show variable here
show = true;
}
Appart from that, if you want to add some extra functionality in a specifical child:
Child class:
#Override
public void action(){
super.action();
//Extra functionality goes here
//You can also access parent's 'protected' fields
if (show){
System.out.println("Shown");
}
}
An example of the use:
Parent p = new Parent();
p.action();//Prints nothing
Child c = new Child();
p.action();//Prints 'shown'

groovy method scope when using a method reference

I have a groovy class that looks up a method reference and then invokes it. The method being invoked is a private method. When the actual class is an instance of the child class, it throws an error that it cannot find the private method, even though it is the public method in the parent that actually calls it.
In this case, I could obviously just call pMethod2() directly and that works, but I'm trying to understand why this doesn't work as written and if there's a way to correct it so it works.
class Parent {
def pMethod1() {
def m = this.&pMethod2
m() // this call fails if the calling class is of type Child
}
private def pMethod2() {}
public static void main(String[] args) {
new Child().pMethod1();
}
}
class Child extends Parent {}
It is a bit confusing, especially if you're used to C / C++. What you get when using the ".&" operator in Groovy is not an address, but an instance of MethodClosure.
The MethodClosure object contains an owner and a delegate object, which is used when resolving the method to call. In your example, the owner and delegate object will be "this", which is an instance of Child. The method to call is simply stored as a string.
So, the assignment
m = this.&pMethod2
is just a shorthand way of writing
m = new MethodClosure(this, "pMethod2")
When you invoke the m() closure, it will try to resolve (at runtime) the method by looking for methods named "pMethod2" in the owner and the delegate objects respectively. Since the owner and delegate is an instance of Child, it will not find private methods located in Parent.
To make your example work you must make sure that the method is visible to the owner and/or delegate of the closure.
This can be done several ways, for instance by changing the access modifier of pMethod2 to protected, or by creating the closure with an instance of Parent; something like this:
m = new Parent().&pMethod2
Note that is is irrelevant that you created the MethodClosure instance in a method where pMethod2 is actually visible. It is also irrelevant that you invoke the closure in a method where it is visible. The method is not visible to the owner or delegate of the MethodClosure, which is what is being used when resolving the method.

List model inherited from QAbstractListModel, list item properties won't update from QML

I'm having a difficult time explaining my problem, so I'm just going to make it as simple and hope it does the job. I'm using Qt5 with QtQuick 2.0.
I've created a MyListModel class that inherits from QAbstractListModel, and holds items of type MyListItem. I use it in a QML ListView as a model: myListModel, and the delegate displays a quantity property from MyListItem, in a lovely TextInput box. Everything works fine.
However, when I change the quantity value from the delegate, the items in the model aren't updated. I know they're not updated, because my setQuantity(long desired_quantity) function, a member of MyListItem, does not run. Long story short, I can't figure out how to actually call the setQuantity function from within the delegate. I can do it manually by adding Q_PROPERTY(long quantity READ quantity WRITE setQuantity) to MyListItem, and then using setContextProperty() to expose a MyListItem myTemp object to QML, and then calling myTemp.quantity = 10. But clearly, if the delegate can't write to the quantity property (it can only read from it), it's not doing the job.
Can somebody point me in the right direction? I feel like I've tried everything the Qt designers could have possibly expected, and I get nothing. And I can't find any documentation that clearly addresses my issue.
The TextInput box will not update your c++ model automatically, you have to do this by yourself. You can do this by adding a slot or Q_INVOKABLE method to you model:
//add a slot to you model
public slots:
setDataInModel(const int index, const QVariant &value);
//or add Q_INVOKABLE method:
public:
Q_INVOKABLE setData(const int index, const QVariant &value);
You have to implement one of these methods so that it changes the appropriate data row in your model. Do not forget to call the dataChanged method inside of the method after update. You then have to call these methods from QML delegate manually when the TextInput is updated:
onAccepted: {
model.setDataInModel(index, text)
}
Here index is a property that is defined in each delegate and text is the text from your TextInput.