Will angular update model value when the viewValue is invalid - javascript

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

Related

Handling numeric property in React form

I use controlled components in my React forms where I'll tie the value of a field in the form to a property of an object I use to collect data -- see below. For numeric fields in my forms, I like using properties of numeric type but I've discovered an unpleasant behavior and want to see how others handle this.
// In my reducer, I have this object that I use to collect data
newItem: {
description: "",
reward: 0
},
// Then, in my component, I'll tie the input to a property of the object
<input name="reward" type="number" value={this.props.newItem.reward} onClick={e => this.myHandler(e)} />
I'll typically set the initial value of a numeric field to 0 which then renders a 0 in the form for the corresponding field. This is a bit unfriendly because user has to first select the value, then type a new one in -- I realize there are keyboard and mouse tricks one can use but most users don't know them and they will simply use the mouse to highlight the value, then type a new one in.
But the real problem I have is that if the user deletes the 0, we end up with NaN being displayed in the field -- see below before and after.
Other than using a string type for my property then parsing it into a number when I need to, what other options do I have to handle this scenario?
This is just a suggestion, but maybe you could have a onChange() function wich would look if the current value is a number, if not, set the value to 0?
onChange(event){
if( isNaN(event.target.value) ){
// do your stuff here
}
}
You could probably get around it by putting a conditional in the value parameter and assigning a default numeric value:
<input name="reward" type="number" value={isNan(this.props.newItem.reward) ? 0 : this.props.newItem.reward} onClick={e => this.myHandler(e)} />
Instead of using the initial value as you are currently doing, you can display a placeholder value like this:
<input type="text" placeholder="0" ...
More info from Mozilla. The '0' will disappear when a user clicks on it.
To fix the NaN issue, one way would be to store the value as a string instead of as a number, and make the form a controlled component. This is detailed in the React Docs.
For example:
The input:
<input type="text" placeholder="0" value={this.state.value} onChange={this.handleChange} />
handleChange:
handleChange(event) {
if (!isNaN(event.target.value) {
this.setState({value: event.target.value});
}
}
This should ensure that only numbers can be entered in the box.

AngularJS: Binding once to an attribute

I am trying to bind once an object key/field to the value of an attribute (data-oldField) so that if its value changes via user input (angular x-editable tables) I can grab the html element via data-newField and get the value of data-oldField so that I can rename the field/key in the object. I tried using the native :: expression to bind once, but the value of data-oldField changes when a change to the field name is submitted so that the values of date-oldField and data-newField are equal afterwards which is precisely what I do not want.
I also tried using the angular-once library and adding the directives once once-attr-field='field' as per the api, but I got the same result.
<tr ng-repeat='(field, value) in user.data'>
<td>
<span editable-text='field' e-name='name' e-form='rowform' data-newField='{{ field }}' data-oldField='{{ ::field }}' e-required>
{{ field }}
</span>
</td>
...
</tr>
Edit:
Plunker
I was unable to get the values of the data-oldfield and data-newfield attributes to show on the view, but if you observe the values of the attributes using your brower's dev tools and press the "Rename Field" button, you can see the that the value of data-oldfield changes even though I'm using one time binding. Maybe I'm misunderstanding how the $watchers work for this kind of binding?
From the angular docs it appears that using :: will be updating the object to a new value but will not be updating to view:
An expression that starts with :: is considered a one-time expression. One-time expressions will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value (see value stabilization algorithm below).
I'm not quite sure I understand the question but one approach would be to
defined a function in your controller that would be called on ng-change that could perform your logic.
Another would be to $watch the model but watching can be expensive
UPDATE
I'm a bit confused what exactly you're trying to accomplish but here is a plunkr that has an ng-change where you can reference the new value and the old value of $scope.user using a copy of the object. You can also use the renameField function however you'd like

Ember 2.1 Input Field Overwriting Computed Property

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)

Angular.js - How I query the input value in text field to app.value

Here is what my controller looks like: http://pastebin.com/C7cx9KaQ
and here's the HTML: http://pastebin.com/UEdwasQu
What I want to do is get the value that user types in, in the input field and use that as the value for the app.value (in my controller, please refer to line 7 of the controller)
I tried adding a ng-model to the input text field and then trying to pass that value in app.value but it did not work - assuming that's because its not in the same controller scope
Would be fantastic to learn how I can implement this

How to properly clean form with invalid input from AngularJS controller?

I have an AngularJS form that contains - among other fields - one of type url. The latter is important as this forces the corresponding input to be a valid URL.
Under certain conditions (for instance, a modal dialog with such a form is to be closed), I want to clear that form programmatically. For that purpose, I implemented method reset that basically clears the corresponding form model by setting $scope.formData = {}. Thus, it sets the form model to a new, blank object.
While that assignment clears all valid fields in the rendered HTML form, it does not clear invalid fields, like an invalid URL. For instance, if the user would provide invalid input ht://t/p as URL, that input would not be removed from the rendered form.
I think this is due to the fact that any invalid URL is not reflected by the model - such an invalid URL just wouldn't "make" it to the model because it does not pass validation in the NgModelController#$parsers array. Thus, in the model - there is no URL at all. Consequently, resetting the form model to {} cannot actually change the model's URL as it has not been set yet.
However, if method reset explicitly sets field $scope.formData.url = "", the invalid URL will be cleared properly (at least, the rendered form won't show it anymore). This is caused by the explicit change of the URL in the model. However, now, model variable formData.url contains the empty string (well, not surprisingly), while by using = {}, all fields would be undefined instead.
While assigning individual fields to "" works as workaround for simple forms, it quickly becomes cumbersome for more complex forms with many fields.
Thus, how could I programmatically reset the form efficiently and effectively - including all invalid input fields as well?
I created a Plunker at http://plnkr.co/c2Yhzs where you can examine and run a complete example showing the above effect.
Specify the type of your button as reset. That will not only call the ngClick function, it will also clear the content of the HTML form.
<button type="reset" ng-click="resetFormData()">Reset</button>
I think this solution is moderately elegant: your plnkr reviewed
The big difference is the initialization of your model object.
I think things gets messed up when a variable becomes undefined, it doesn't get updated anymore.. it should be connected (veeeery) deeply with how validation works (docs link)
Returning undefined in that case makes the model not get updated, i think this is exactly what happens behind the curtain
PS: you can recycle resetImplicitly for all your forms in the webapp :)
After trying several answers without success in similar questions, this worked for me.
In my controller:
$scope.cleanForm = function() {
$scope.myFormName.$rollbackViewValue();
};
Just call with some ng-click or any way you want.
Cheers
The Thing is tag is of type "url" which means
if user will enter specifically a valid url then only it will set values of model
If user will expicitly reset it which means setting model values to "" will again make textbox empty .
It is looking like it is setting the values but actually not ,so when you set its value to "" .Angular will set modal value to ""
Lets take another example : put replace "text" with "email"
<input type="email" ng-model="formData.name" />
<br />URL:
<input type="url" ng-model="formData.url" />
<br />
In above code If you will enter invalid email it will not set the values of email's model.
You probably need to make a copy of the model in its pristine state and set the model to pristine when you reset.
There's a good example here:
http://www.angularjshub.com/examples/forms/formreset/
The url form fields are passed into the model only if they are valid. Thus in case of an invlaid-url entry in the form, the scope variable is not assigned with the model and clearing the forms entry by assigning an empty object to the model will still persist the value at the UI front.
The best alternative to this is to assign the model associated with the form data with a null. A similar answer appears here:
https://stackoverflow.com/a/18874550/5065857
ng-click="formData={};"
just give like this ,
<button ng-click="formData={}">(1) Reset Full Data: formData = {}</button>
Reset your form data directly in ng-click itself.

Categories

Resources