Angular.js: update binding after manual modification - javascript

I'm only starting to dive into angular.js and have found this issue that I can't seem to get around. Consider this simple code:
<input type="text" ng-model="test">
<input type="text" value="{{test}}">
When I write in the first field, the second one is updated nicely. When I write in the second field and then go back to the first one, the binding is not updated anymore. Interestingly though, the HTML attribute value does get updated - it's just not displayed.
Equivalent (at least roughly) code in vanilla javascript does not suffer from this:
<input type="text" id="model">
<input type="text" id="binding">
<script>
var model = document.getElementById("model");
var binding = document.getElementById("binding");
model.addEventListener("keyup",function() {
binding.value = model.value;
});
</script>
Here's a fiddle for you to test both: http://jsfiddle.net/Q6b5k/
Any idea why this happens when using angular.js and how to fix this?
[EDIT] Judging by the initial replies, it appears I have not made it clear. I do not want the second field to update the first one. The binding is to be one-way only, e.g. to allow filtering or even manual corrections (such as automatic creation of a URL alias in a blog post creation form). http://jsfiddle.net/Q6b5k/1/

The value attribute is only used when rendering the initial HTML. After the page load, everything else happens in the Angular Event Loop and therefore you need to do something that event loop can pick up. You can use ng-change for what you are looking to do:
<input type="text" ng-model="test" ng-change="test2=test.toLowerCase();" />
<input type="text" ng-model="test2"">

This happens because {{value}} does not create a binding, it is used for interpolation.
The simplest solution is to use ng-model in both the fields
<div ng-app>
Angular.js:<br>
<input type="text" ng-model="test">
<input type="text" ng-model="test">
</div>
Demo: Fiddle

Related

Chrome extension: JQuery triggering 'keyup' does not update the 'input' value - website uses knockout JS

I am writing an chrome extension on top of a website that I figured runs 'knockout JS'.
Consider the following HTML element:
<input type="text" class="form-control text-right" id="amount" autocomplete="off" data-bind="value: amount, valueUpdate: 'keyup'">
I am trying to write a bot that fills this field with a particular value. I have included JQuery as a dependency in the extension.
I tried the following using the Jquery code. The objective is to update the value of the element to say 200.
$('#amount').val("200");
$('#amount').trigger("keypress");
$('#amount').trigger("keyup");
The code seems to update the value of the input visually, but the dependent knockout JS functions do not get triggered. I have not used Knockout JS before.
How do I trigger the knockout JS events ?
Update
I hadn't paid attention that you were running a bot on the page. You should be able to get Knockout to recognize the change by
$('#amount').val("200");
$('#amount').trigger('change');
vm = {
amount: ko.observable(100)
};
ko.applyBindings(vm);
vm.amount.subscribe(function(newValue) {
alert("Changed");
});
setTimeout(function() {
$('#amount').val(200);
$('#amount').change();
}, 800);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input id="amount" data-bind="value: amount" />
Original reply for anybody who might be writing Knockout
You should probably go through the Knockout tutorial.
If you're going to use Knockout, you will not be interacting directly with the DOM, as jQuery does. Instead, you will manipulate variables in the viewmodel (generally speaking, the viewmodel is all the JavaScript code you write that is not attached to Knockout's ko object). In this case, the input's value is bound to the amount variable. To change what's in the input, set the contents of the variable:
amount(200);
(Knockout uses "observable" variables, which are setter-getter functions, rather than simple values).
You can use below code to fulfill your requirement.
<input type="text" class="form-control text-right" id="amount" autocomplete="off" data-bind="value: amount , valueUpdate: 'keyup'">
<p><span data-bind="text:amount"></span></p>
<script src="knockout-3.4.0.js"></script>
<script>
var obj = {amount:ko.observable('200')}
ko.applyBindings(obj);
</script>

knockout textinput modify observeable not updating text

i´m using textinput data-binding off the latest knockout version.
on an input like:
<input type="text" placeholder="name" data-bind="textinput:vm.found().term">
and it works just like a charme, problem:
when i modify the value with some other script like:
vm.found().term("somecontent")
the input does not change?
i need the value of the textinput to change when i change the observable
the doc says nothing about textInput
You should never have raw, deeply nested bindings like you have there. Assuming the found value has changed, it the text box will still be bound to the previous found object. You probably should be using a with binding somewhere.
<div data-bind="with: vm.found">
<input type="text" placeholder="name" data-bind="textinput: term">
</div>

Angularjs Form/Field validation using JavaScript function without directives

Is there a way to validate a field in angular without using a directive?
For example: I want to make following validation on an input field.
If field is empty we should show "Field must contain a value" message.
if field contains alpha Numeric characters we should show "Field can contain only digits".
An EVEN number - message to the user "Value must be an even number".
I want to make following validation in a call to JavaScript function.
I googled around and saw that there is a way to use ng-valid and $error , however I was not managed to make it work.
Code below is according to one of the answers I got:
<div ng-app>
<form name='theForm' novalidate>
<input type='text' name='theText' ng-model='theText' ng-pattern='/^[0-9]+$/'/>
<span ng-show='theForm.theText.$error.pattern'>Field can contain only digits</span>
<span ng-show='theText.length<1'>Field must contain a value</span>
<span ng-show='theText%2!=0&&document.getElementsByName("theText").value!=""&&!theForm.theText.$error.pattern&&!theForm.theText.$pristine'>Value must be an even number</span>
<br/><input type='submit' value='Submit' />
</form>
I want to take what inside the last [span] and put inside a JavaScript function in order to make it more generic and eventually change only JS and not the HTML when conditions are changing
Can someone please advise? a working example would be great.
I'm surprised no one has mentioned ui-validate
$scope.isOdd = function($value){
return $value % 2;
}
...
<form name="myform">
<input ng-model="myVal" name="value" required
ng-pattern="/^[0-9]*$/" ui-validate=" 'isOdd($value)' "></input>
<pre>{{myform.value.$error|json}}</pre>
</form>
Doesn't get any simpler than that, and it's PROPER AngularJS validation (not silly watches)
Here's a working demo
Take a look at the angularjs form documentation - http://docs.angularjs.org/guide/forms . In general, it is based on the HTML5 attributes like required, min, max, etc.
To get, for example, your first requirement done - "an empty field should show "Field must contain a value" message, yo uwould do something like that:
<input type="text" ng-model="user.name" name="uName" required /><br />
<div ng-show="form.uName.$invalid">
<span ng-show="form.uName.$error.required">Field must contain a value.</span>
</div>
For digits only field you can use the pattern attribute with a matching regular expression (example: http://www.wufoo.com/html5/attributes/10-pattern.html).
For even number validation, I'm not sure - I think you'd have to go with custom validation for that (meaning you'd have to create a directive) or use the pattern attribute somehow.
Last but not least - remember to add novalidate to the <form> tag. Otherwise the browser will try to validate your fields as well and you don't want that:
<form ... novalidate>
...
</form>
I know the question is old and I know you didn't want a directive but you may consider using a directive if it's "Angular" way... Well here is my Angular-Validation. I made a project on Github and I think that it just rocks compare to whatever is/was available...I based myself on the excellent Laravel PHP Framework and made it available under Angular... It is so crazy simple, you need 2 lines 1 line of code, 1 line for the input, 1 line for error display, that's it... never more and never less!!! Enough said, let's give some examples:
<!-- example 1 -->
<label for="input1">Email</label>
<input type="text" validation="email|min_len:3|max_len:25|required" ng-model="form1.input1" name="input1" />
<!-- example 2 -->
<label for="input2">Alphanumeric + Exact(3) + required</label>
<input type="text" validation="alpha|exact_len:3|required" ng-model="form1.input2" name="input2" />
So I can define whatever amount of validation rules (already 25+ type of validators) which I want in a simple directive validation="min_len:2|max_len:10|required|integer" and the error message will always display in the next <span> Don't you guys like it already? 1 line of code for your input, 1 line of code for the error display, you can't be simpler than that...oh and I even support your custom Regex if you want to add. Another bonus, I also support whichever trigger event you want, most common are probably onblur and onkeyup. Oh and I also support multiple localization languages via JSON external files. I really added all the imaginable features I wanted into 1 crazy simple directive.
No more clustered Form with 10 lines of code for 1 input (sorry but always found that a little extreme) when the only thing you need is 2 lines, no more, even for an input with 5 validators on it. And no worries about the form not becoming invalid, I took care of that as well, it's all handled the good "Angular" way.
Take a look at my Github project Angular-Validation... I'm sure you'll love it =)
UPDATE
Another candy bonus! To make an even more smoother user experience, I added validation on timer. The concept is simple, don't bother the user while he's typing but do validate if he makes a pause or change input (onBlur)... Love it!!!
You can even customize the timer as per your liking, I've decided to default it to 1 second within the directive but if you want to customize you can call as for example typing-limit="5000" to make a 5 sec. timeout. Full example:
<input type="text" ng-model="form1.input1" typing-limit="5000" validation="integer|required" name="input1" />
<span class="validation text-danger"></span>
UPDATE #2
Also added input match confirmation validation (ex.: password confirmation), here is a sample code
<!-- input match confirmation, as for example: password confirmation -->
<label for="input4">Password</label>
<input type="password" name="input4" ng-model="form1.input4" validation="alpha|min_len:4|required" />
<label for="input4c">Password Confirmation</label>
<input type="password" name="input4c" ng-model="form1.input4c" validation="match:form1.input4,Password|required" />
UPDATE #3
Refactored the directive so that the requirement of having a <span> to display the error is unnecessary, the directive now handles it by itself, see the code change reflected on top.
DEMO
Added a live demo on Plunker
Well you can try to create a func
<span ng-show='isEven(theText)'>Value must be an even number</span>
$scope.isEven=function(data) {
if(data) {
return data%2===0
}
return true;
}
The method can either be defined on the current controller scope or on $rootScope.
Not a very angular way, as directives would be better but i think it would work.

Correct syntax for binding to a form in jsviews (commit 26)

I am experimenting with Boris Moore's jsrender/jsviews libraries and am using the current version at the moment (commit 26). (I realize the API is in flux but would like to practice using it)
I've looked at the demos here:
http://borismoore.github.com/jsviews/demos/index.html
But I am having trouble determining the data-link syntax. In some of the demos the syntax is data-link="{:FirstName:}
I don't understand why the 2 colons. I assume the 1st colon means no HTML encoding would be done, but have no idea about the 2nd one.
In other places I see syntax like data-link="address.street" Here there are no curly braces or colons at all. I wonder when you need them and when you don't. Also I don't follow how you would specify if you want one-way or two-way binding. Or if you wanted binding to trigger in response to a key press instead of blur.
Here's an example I'd like to setup properly:
<div id="form">
<p>
<label>First Name</label>
<input type="text" name="FirstName" data-link="FirstName"/>
</p>
<p>
<label>Last Name</label>
<input type="text" name="LastName" data-link="LastName"/>
</p>
<p>
<label>Full Name</label>
<input type="text" data-link="FirstName + ' ' + LastName"/>
</p>
<p>
<label>Gender</label>
<select name="Gender">
<option value="U">Unknown</option>
<option value="M">Male</option>
<option value="F">Female</option>
</select>
</p>
</div>
<script>
var data =
{
FirstName: "Bill",
LastName: "Willis",
Gender: "M"
};
$("#form").link(true, data); //What is the 1st parameter (true) about?
</script>
I don't know how to bind to the select control.
I'd appreciate any explanation of how this should be done.
data-link="a.b.c" is the shorthand syntax, and is equivalent to the full syntax data-link="{:a.b.c:}" on inputs (which gives you two-way binding) and data-link="{:a.b.c}" for most other elements (i.e. not form elements for user input, so of course it is one-way binding).
See https://github.com/BorisMoore/jsviews/issues/136 for some details.
If you want to do non-default binding you use the full syntax, e.g. with convert or convertBack as in data-link="{cvt:a.b.c:cvtBack}", or one-way binding on an input, as in data-link="{:a.b.c}".
So the colons both specify the direction of the binding, and allow you to add a converter for that binding.
One-way 'to source' is not currently directly supported, but is possible by using converters. Binding to select is shown in several examples, such as this one, or this one.
Currently the trigger is onblur (or onchange) - but it will soon be possible to set that declaratively too. Right now it requires code to achieve it - as in this example.
The code for all the demos is here.

where to pass quantifying data values for formula fields?

What is a common way to pass data for formula fields, to specify a quantifier. I would currently do as follows:
<input type="text" name="myfield" class="inputfieldstyle quantified" id="q_12" value="foo" />
where q_12 is generic.
But there some inherent problems with the approach:
What if i want to give it an id for some js/css reason?
q_12 is not easy to read with js:
var quant =
parseInt(element.id.split('_').pop())
id is not made for passing values
How should I handle this? Is there a common way? Is there a way suggested by w3c?
A good and simple way is to use hidden fields :
<input type="hidden" name="myname" value="my_value" id="my_id">
You could extend the hidden fields idea of Guillaume Lebourgeois. If you're worried about having two inputs for each, you could always adopt the "data-" attribute approach as detailed in the following link: http://ejohn.org/blog/html-5-data-attributes/
<input type="hidden" name="myname" id="my_id"
data-myData1="somedata" data-myData2="somemoredata" value="" >
and then use getAttribute to return the value (http://www.devguru.com/technologies/javascript/17457.asp):
document.getElementbyId("my_id").getAttribute("data-myData1")
document.getElementbyId("my_id").getAttribute("data-myData2")
Or if you are using jQuery:
$("#my_id").attr("data-myData1")
Of course, you would have to roll this up into the value before passing across pages, but its still a possiblity.

Categories