Ember 2.1 Input Field Overwriting Computed Property - javascript

I have a computed property that listens to a model and looks something like:
groups: function() {
let g = this.get('model.items.groups').map(function(obj) { return obj.group; });
return g.join(',');
}.property('model.items.groups'),
In my template, I have the following input field:
{{input value=groups type="text" class="form-control" placeholder="Testme"}}
I noticed that after providing input through the UI, the value within Ember inspector for groups becomes a string and no longer a computed property. How do I avoid this in Ember 2.1 and have it merely update the computed property?

That happens because the {{input}} helper uses two-way binding by default. When you write in the input field it will write to the value property.
I've been using dockyard's one-way-input addon, that provides an input component with one-way binding by default.
{{one-way-input
value=groups
update=(action 'updateSomething')
}}
And then in wherever you're using the component:
actions : {
updateSomething(value) {
//Do Something with the value and update model.items.groups?
}
}
This way, the value is always read from the groups computed property and the action updates the source of the value (and not the computed property)

Related

Vue.js get all v-model bindings

With Vue.js you can you bind form input to a property:
https://v2.vuejs.org/v2/guide/forms.html
I am working on a project where I 'dynamically' generate a form though. Here the v-model bindings are just attributes that are being set based on the name that an input has.
The problem though is that I am left wondering how to properly get these v-model bindings. So far all I have see is people manually setting a property on their Vue instance for the binding:
new Vue({
el: '...',
data: {
checkedNames: []
}
})
Is it possible to somehow grab all of the v-model bindings though without setting up the data properties manually?
When creating a dynamic form with a variation an dynamic number of fields this would help out a lot.
I guess one option is simply retrieving the name atributes from the input with javascript but I am hoping there might be something in place already since v-model is probably calling a setter that might already be known in the Vue instance.
Reworked the example from the answer:
https://jsfiddle.net/yMv7y/2477/
According to the official documentation:
it’s possible to add reactive properties to a nested object using the Vue.set(object, key, value) method.
This means that your starting data can be something like:
{
customForm: [],
values: {}
}
Let's assume customForm is an array of field objects that describe a bunch of fields in your custom form. It's empty at the beginning because you say your form will be created dynamically.
Once you generate that dynamic data, all you need to do is assign it to customForm and loop through it to add reactive properties with the aforementioned Vue.set method.
Here's a JSFiddle with an example. I'm using this.$set, but that's just an alias for Vue.set.

Will angular update model value when the viewValue is invalid

I have a form and an input. The input is bound to a value in the controller via ng-model. Now I have a custom validator which invalidates the input's value in certain circumstances. But I can't find out if the model value is updated if my validator invalidates the value. I can't $watch in my controller so I have no idea how I could find out this. Pseudocode here:
(hint: snippet won't run)
class Controller {
constructor() {
this.myVal = 0;
}
}
<input type="number"
id="max"
name="max"
ng-model="ctrl.myVal"
restrict-value="form.min.$viewValue" />
Now my problem can be seen. The restrict-value directive will register a $validator on the ngModel and will return false if the value of the input field is greater than another field (min). If max's value is lower than min's I don't want to update the model value. Can I do this?
In browsers that follow the HTML5 specification, input[number] does not work as expected with ngModelOptions.allowInvalid. If a non-number is entered in the input, the browser will report the value as an empty string, which means the view / model values in ngModel and subsequently the scope value will also be an empty string.
from here

Best practices for the input helper in new Ember components

I'm currently learning about Ember's new data-down, actions-up paradigm for components. As discussed here, however, sometimes I want to allow the child component to modify the property explicitly. This is where the mut helper comes in: it creates a wrapper for the passed in value, containing a (readonly?) value and a function to update it. The example on that page is for a simple button which increments a counter.
How does this concept work if I'm using the input helper inside a component? For example, let's say I'm building a form which consists of a bunch of special form components:
// templates/index.hbs
<form>
{{form-control value=(mut model.firstValue)}}
{{form-control value=(mut model.secondValue)}}
</form>
If the form-control component just has the task of wrapping the input control, how do we use the passed-in mut object correctly? Is it something like?
// templates/components/form-control.hbs
{{input type="text" value=attrs.value.value input=attrs.value.update}}
My thinking here: the value of the input element is set to the value of the mut object, and whenever the input value changes (HTML5 input event) the update method of the mut object is called to set the model property to the new value. It seems there's something wrong with my thinking though, because this doesn't work. What is the "standard" way of doing this now? I'm using Ember 1.13.8.
In classic components (as opposed to glimmer components), all bindings are mutable, so it is not generally necessary to use the mut helper. The following should work fine:
// templates/index.hbs
<form>
{{form-control value=model.firstValue}}
{{form-control value=model.secondValue}}
</form>
// templates/components/form-control.hbs
{{input type="text" value=value}}
The intended use of both the mut helper and of attrs is for glimmer components, also called angle bracket components, which are currently not released in Ember.js' stable releases.

custom knockout binding in object literal

how can i implement multiple custom knockout bindings that can be declared in an object literal?
basically instead of doing this:
<input data-bind="customBinding1:observable1, customBinding2: observable2 }" />
I would like to be able to do this:
<input data-bind="customBinding0: { customBinding1: observable1, customBinding2: observable2 }" />
thanks in advance.
With Knockout, bindings are specified in name/value pairs, where name is the name of the binding, and value is the value that will be retrieved within the binding using valueAccessor().
It sounds like you may be wanting to pass multiple values in to a binding, like your kendo example shows. Although each binding can only have a single value, that value can be anything. This means you can pass in an object literal as the value, and the object can have as many properties as you want. These properties can also be of any type that you want - you'll just need to handle them correctly inside your binding.
Here's a simple example:
View
<div data-bind="myBinding: {setting1: viewModelProperty1,
setting2, viewModelProperty2}"></div>
Binding
ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor) {
var options = valueAccessor() || {};
//this gives you the value of setting1
var setting1 = ko.utils.unwrapObservable(options.setting1);
//if you need to do something just when `setting1` changes,
// add a subscription to the value like so:
if( ko.isObservable(options.setting1) ){
options.setting1.subscribe(function(newValue){
//do something because the setting1 value changed
});
}
}
};
You also have the option of specifying multiple bindings, each with its own value, and referencing the additional bindings and values from within the first one. Knockout's options and optionsText bindings are an example of this approach.
Excellent Resource: http://www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html
Take some time to study and experiment with the examples at the link above. There's a lot of good information here that covers what you need to do.

Angular ng-option access multiple properties

Say I have a backend call which returns a list of objects (and properties), and I use ng-option to stick one of the properties (the name) into the dropdown list, which is using ng-model to attach itself to my model object.
My problem comes in when I need to access other properties of the selected object. ng-option lets me bind objects to that dropdown, which is great. However, if I pull the name out to bind that to my model:
<select ng-model="myModel.name" ng-options="fieldlist.fields.name as fieldlist.fields.name for fieldlist in metrics">
I lose reference to the rest of the object's properties. I need to use another property of the selected object, say fieldlist.fields.location, to perform some other action in an ng-change function. So
Is this possible? Is my Angular naiveté showing too much?
I believe you can do:
ng-model="myModel" ng-options="fieldlist.fields as fieldlist.fields.name for fieldlist in metrics"
Assuming you want myModel to contain all the fields in the selected fieldlist
Per your comment - and this may not be best practice, just my initial thought on how I would do it, you could do something like:
ng-model="selectedItem" ng-change="setSelectedItem()" ng-options="fieldlist.fields.name as fieldlist.fields.name for fieldlist in metrics"
and then in your controller
$scope.setSelectedItem() = function() { $scope.myModel.name = selectedItem.name; };
or remove the ng-change and do
$scope.watch(selectedItem, function() { $scope.myModel.name = $scope.selectedItem.name }
And then you can get whatever property you need from $scope.selectedItem
A little late, but good information i found if anyone could use it. Its still a little odd, but it makes it a little cleaner.
Angular released a ngModelOptions directive which, among other useful things, allows you to define the ngModel as a getter/setter function. Using this, you can remove that pesky ng-change or watch (and possibly a $Digest?). Simply place your update function as the ng-model and set your items that way.
<select ng-model="updatefielset" ng-model-options="{getterSetter:true}" ng-options="fieldlist.fields as fieldlist.fields.name for fieldlist in metrics">
$scope.updatefielset(item) = function()
{
if(angular.isDefined(item)
{
$scope.myModel.A = item.A;
$scope.myModel.B = item.B;
$scope.Val = item;
}
return $scope.Val;
};
https://docs.angularjs.org/api/ng/directive/ngModelOptions

Categories

Resources