I have a computed property which is dependent on A and B:
#computedFrom(A, B)
get property() {
}
The property is used in element which has repeat.for (5 elements in total):
<element repeat.for 1 to 5 elementProperty=$"{property}">
</element>
When value A changes, I would expect property() to be called just once, and all elements updated with the new value.
But property() is called 6 times.
Why?
Edit:
When I do this...
<template repeat.for 1 to 5>
<element elementProperty=$"{property}"></element>
</template>
...property() is called 6 times too.
Is this how it should work?
If you have a repeat.for, then the source property of any bindings in it is called for each child element that is rendered. This is normal behavior as they are all separate binding instances.
If your binding source changes, all binding targets (in this case 6) need to be updated and that happens by calling the source property. Computed bindings tend to be such simple computations that this is generally not an issue.
If your computed bindings are computationally expensive, you might want to consider using a property observer for the dependent properties and simply setting the computed property when any of them change, rather than letting the binding engine call it on binding.
EDIT
To clarify: this doesn't really have anything to do with computedFrom. A non-computed property would also be read 6 times but there is no getter to hook the debugger on, so you can't see that directly.
Related
I'm making a Form wrapper and I'm wondering how to handle data object prop.
From what I have seen out there, there are some (like FormKit) that mutate the prop object that holds the data. This is not a recommended way according to the official docs. Then there are those (like VueFormulate) that create a shallow copy of the data object before emiting the changed object. To support nested data object you need to deep copy the data object on every change. This seems wasteful with large forms.
Is there an alternative where you don't deep copy an object and you don't mutate object prop?
You could possibly use v-model. as the docs will say, it's shorthand for the child component having a property bound from the parent and when a change event occurs you emit an update event from the child to the parent to have the parent update the property, and the child will subsequently sync to the new value.
ie:
childComponent *has value change*
onChange (value) => this.$emit("updateValue", value)
parentComponent *recieved "updateValue" event*
onUpdateValue(value) => this.parentValue = value
I'm working on a component which is a kind of glorified input control, which will save a lot of the repetitive HTML of forms with Bootstrap grids (having to put a label next to each one, assign a 'for' attribute to it, assign a 'form-control' class to the input, etc.). The idea is that the component contains an input control with default values (such as the 'form-control' class) already set, label prepended, etc.
The HTML 'input' control as a whole bunch of optional attributes, some of which I may wish to use at some point - readonly, disabled, placeholder, etc. Do I actually have to declare all of these upfront, as it were, in my component's properties, if I may use one or more of them? This is a bit of a nuisance and rather cumbersome if true. It would be handy if all attributes which weren't explicitly declared were simply made available in the component's scope.
This is, I imagine, a common enough requirement that maybe there's another way of doing this?
You don't need to declare all of them, you can use v-bind to bind an object of optional attributes. So, in your parent you can do:
<custom-input :optional-attrs="{placeholder: 'Type something!'}"></custom-input>
Then in your component simply add it as a prop:
props: {
optionalAttrs: {}
}
And use v-bind on your input in your component:
<input type="text" class="form-control" v-bind="optionalAttrs">
Here's the JSFiddle: https://jsfiddle.net/rww551og/
You have to declare all props which CAN BE USED, but you have to add REQUIRE: TRUE only on those which are required. That's all.
I am adding a "rounding" business rule to round a decimal property value to the number of decimal places specified in a separate integer property. This works nicely if both properties are members of the business object in question. As in the following VB.Net code...
BusinessRules.AddRule(New Round(_decimalProperty, _precisionProperty))
I have a private Round class that inherits from CommonBusinessRule and its constructor is as follows:
Public Sub New(decimalProperty As IPropertyInfo, precisionProperty As IPropertyInfo)
MyBase.New(decimalProperty)
InputProperties = New List(Of IPropertyInfo)()
InputProperites.Add(decimalProperty)
InputProperties.Add(precisionProperty)
End Sub
This triggers the rule Execute whenever either property changes, and the Execute code rounds just exactly like I want.
The Problem: I now have a situation where the precisionProperty is a property of the Parent business object. When the CSLA method for adding Business Rules for the Child Business Object is called, the Parent member of the Child Business Object is null, so I can't get to a reference of the parent's property. Is there any point in time AFTER the Parent field is no longer null, that I am allowed to add a new Business Rule? If so in what method? Is there another approach?
We have looked into passing down a reference to the parent business object (via constructors) to the child, but have decided against this approach for now (the child is actually 6 levels deep, and it appears this would require rework of our code generation schemes).
The parent property in the BusinessBase is generally used by the BusinessListBase to keep a relationship with its children. The parent property really isn't(shouldn't be?) used outside of that.
When I have a parent object with a property that affects child objects, I put the rule in the parent object that will then invoke any rules on the child object. You can pass in any values you like, even to the point of having a copy of the property on the child and just setting that as the parent property changes.
I am trying to populate a dependency property from XAML. The dependency property is an IEnumerable<KeyAction> where KeyAction is a complex type.
<loc:MyType.KeyActions>
<loc:KeyAction Action="Show" Key="Space" Modifiers="LeftCtrl" />
<loc:KeyAction Action="Hide" Key="Escape" />
</loc:MyType.KeyActions>
Now, this causes the KeyAction property to be 'declared twice' because XAML interprets each item as a candidate for the property, instead of items in a list.
For this to work, it would need to look something like:
<loc:CompletionPopupView.KeyActions>
<sys:List`KeyAction>
<loc:KeyAction Action="Show" Key="Space" Modifiers="LeftCtrl" />
<loc:KeyAction Action="Hide" Key="Escape" />
</sys:List`KeyAction>
</loc:CompletionPopupView.KeyActions>
And I'd need to add namespaces, and the generic syntax is probably even more terrible, if even doable. Is there any way to make the first example work?
There are two different ways you can make this work. One looks exactly like your first example, but requires changes to your class and doesn't operate quite the way you're asking for (which might or might not be a problem to you); the other acts exactly like you're asking but is a little more verbose. You can decide which one is better for you.
Option 1: Adding to a collection
XAML has magic shorthand syntax for initializing collections, using the exact syntax you show in your first example. However, it only works if the property type implements IList. (Yes, that's really the non-generic IList -- not normally a big deal though, all the generic collections that ship with .NET implement both IList<T> and IList.)
So you could do your first example, but only if your KeyActions property was declared as a type that implements IList. For example, you could change your property to:
public ObservableCollection<KeyAction> KeyActions { get {...} }
And then just put multiple child elements inside your property, and it would add them to the collection:
<loc:MyType.KeyActions>
<loc:KeyAction Action="Show" Key="Space" Modifiers="LeftCtrl" />
<loc:KeyAction Action="Hide" Key="Escape" />
</loc:MyType.KeyActions>
This isn't quite like what you asked for though, because the XAML doesn't create a new collection -- it adds to the existing collection. So if you choose this option, your class needs to instantiate the collection in its constructor (KeyActions = new ObservableCollection<KeyAction>();), so that you don't get a null reference exception when you start trying to Add elements to it.
Option 2: Creating a new collection
If you do need to create a new collection and assign it to your property, that's doable too. Unfortunately, XAML2006 (the flavor still used by WPF) only supports generics on the root element of the entire document -- so you can't instantiate a List<T> and assign it to a property.
But that's okay; you can use the same workaround that WPF does. Just create your own non-generic class that descends from a generic list.
public class KeyActionCollection : ObservableCollection<KeyAction> {}
Then you can instantiate it in XAML:
<loc:CompletionPopupView.KeyActions>
<loc:KeyActionCollection>
<loc:KeyAction Action="Show" Key="Space" Modifiers="LeftCtrl" />
<loc:KeyAction Action="Hide" Key="Escape" />
</loc:KeyActionCollection>
</loc:CompletionPopupView.KeyActions>
If you choose this option, you can keep your property declared as IEnumerable<KeyAction> if you wish. The custom list is only necessary to populate the list from XAML.
You could even combine both approaches: make the property read/write and of type KeyActionCollection, instantiate it in your constructor, and then XAML can choose whether to add to the existing collection using the shorthand syntax, or create a new collection; and runtime code could make the same choice.
I have a ListView bound to an ObjectDataSource, I'm passing some custom parameters to the Insert and Update methods on my bound class methods by adding them to the event.Values map in the ListView ItemInserting/ItemUpdating events.
However when I try to do the same thing on the ItemDeletingEvent the additional parameters do not seem to be passed to the datasource ( If I register a listener for ObjectDataSource.ItemSourceDeleting I only see one parameter, effectively the 'id' of the row).
Is this an expected behavior? I can't see anything in the documentation that indicates as such.
I found a solution -
I Added a 'DeleteParameter' value with the same name as my desired 'custom' parameter to the ObjectDataSource declaration.
Then in the ItemDeleting Event get the ObjectDataSource.DeleteParameters["myparam"] and set the DefaultValue property. Seems like a hack, but it does work.