I have a text input bound to a model value, but I can't figure out how to change the input value programmatically and have the change propagate to the model.
I understand that because I'm updating the value external to the angular scope that I need to explicitly call $scope.$apply(), but it's not working.
HTML:
<input id="test_input" ng-model="test_value">
Controller:
$scope.test_value = 'abc'; // starting value
Console:
$('#test_input').val('xyz');
$('#test_input').scope().$apply();
$('#test_input').scope().test_value;
-> 'abc';
ngModel listens for "input" event, so you need to trigger that event after setting the value:
$('#test_input').val('xyz');
$('#test_input').trigger('input');
$('#test_input').scope().test_value;
Related
I have a customer who is a member of a web site. He has to fill a form every time which is really very often. That's why he wants me to develop an application for him to make this process automatic. When I use the webBrowser control to manipulate it, I am able to login but after that there are fields that contains data-binding. These fields are the ones I need to manipulate. When I push the data to necessary fields, it's not working, because in the html tag, there is no value attribute, instead it has data-binding. So my question is how can I manipulate and push data to these fields?
Thank you so much for your all help in advance.
Knockout uses data-binds to listen to changes in an input and update an underlying model. For example, the value binding listens to change events and writes the new value to a data-bound observable.
If you update a value attribute through code, the change event isn't triggered. You'll see the new value in the UI, but the javascript model won't be updated.
You can combat this by explicitly triggering a change. Here's an example:
Type in the input: you'll see a console.log that shows knockout gets updated
Press the button to inject a new value: you won't see a log: knockout isn't updated
Press the last button to trigger a change event. You'll notice knockout now updates the model.
Of course, you can combine the two click listeners into one function. I've separated them to get the point across.
// Hidden knockout code:
(function() {
var label = ko.observable("test");
label.subscribe(console.log.bind(console));
ko.applyBindings({ label: label });
}());
// Your code
var buttons = document.querySelectorAll("button");
var input = document.querySelector("input");
buttons[0].addEventListener("click", function() {
input.value = "generated value";
});
buttons[1].addEventListener("click", function() {
// http://stackoverflow.com/a/2856602/3297291
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
input.dispatchEvent(evt);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input type="text" data-bind="value: label">
<button>inject value from outside</button>
<button>let knockout know something changed</button>
Why do we need to use ng-model to make sure that validation works. For instance, in this code if I remove ng-model attribute then validation breaks but it works as long as there is ng-model attribute no matter what is the value of attribute is. So what's the significance of ng-model in this case? Why do I have to use though it's value does not make much difference?
The value of ng-model makes all the difference. Not the initial value however, which you are correctly asserting seems to be irrelevant. As soon as you type something into that input box Angular magically assigns the value to the variable assigned to ng-model.
Subsequently, the value of ng-model is what Angular's validation code is validating! The data has to get from your fingers to the code somehow and that's the ng-model.
Let's say you have typed into an input box with ng-model on it: "I am so cool."
<form ng-controller="SuperController">
<input ng-model="somethingAwesome" />
<button ng-click="someAction()">Click me!</button>
</form
Inside your controller you can access that value on the $scope.
function SuperController ($scope) {
$scope.someAction = function () {
console.log($scope.somethingAwesome)
// "I am so cool."
}
}
If you set the value inside your controller.. your input box will display that value.
function SuperController ($scope) {
$scope.somethingAwesome = 'You are so cool!'
}
Angular's validation functions read the value of the stuff on your $scope, which contains the values of items in your view that have the directive ng-model.
https://docs.angularjs.org/api/ng/directive/ngModel
I have made a simple example using angularjs. This example contains three radio inputs, each of which have to call a function on change (ng-change => console.log). Unfortunately, the function its only triggered the first time any radio input is selected.
HTML:
<div ng-app="myApp" ng-controller="radioGroupController">
<div ng-repeat="value in values">{{value}}
<input type="radio" name="name" ng-model="val" value="{{value}}" ng-change="logChange(val)" />
<hr/>
</div>
</div>
JS:
angular.module('myApp', [])
.controller('radioGroupController', ['$scope', function ($scope) {
$scope.values = ['Option1', 'Option2', 'Option3'];
$scope.logChange = function (newValue) {
console.log('Changed to ' + newValue);
};
}]);
Am I doing something wrong or is this the expected beheaviour?
EDIT: fiddle
Couple of issues/changes:-
1- Change value={{value}} to ng-value="value" because ng-value - Binds the given expression to the value of input[select] or input[radio], so that when the element is selected, the ngModel of that element is set to the bound value.
2- You need to set the selected value on the property on parent scope, you have ng-repeat and you really are setting value of the child scope, so each radio has its own child scope and its value never changes so ng-change is not triggered.
3- You do not need to pass the model value though logChange scope will already have it.
Try:-
In your controller add:-
$scope.selected = {};
and view set the model as a property on selected property of controller scope instead of ng-repeated child scope's val property:-
<input type="radio" name="name" ng-model="selected.val"
ng-value="value" ng-change="logChange()" />
Plnkr
You can change ng-change to ng-click, then it fires every time you actually click on the button.
Here is a JSFiddle.
Depending on what you want to achieve, consider $watch or ng-model for your purpose.
If you bind ng-model to "values" or whatever, you can check which
value it has and work with that. Angulars advantage is exactly this
two-way-databinding without doing anything. No need to call a
function to pass an argument.
Problem:
Running into an issue where I'm trying to use ng-change on a text field. The snag is I'm using a slider to change a value of this text field.
The ng-change event works when I click into the text field and start typing: logOutValue() fires and logs out in my browser.
The HTML:
I'm using this Angular range slider
—> (Example)
<div ng-repeat='obj in testObjects'>
<rzslider rz-slider-model="obj.max">
<form>
<input value='{{ obj.max }}' ng-change='logOutValue(obj)' ng-model="testObjects[obj.name]">
</form>
</div>
The slider fills in the text input's value via obj.max. This works. Again, when clicking in text field and typing, the value is logged out.
In Controller:
testObjects = {};
$scope.logOutValue = function(obj){
console.dir(obj);
};
Other ideas
I tried to use a $watch but that only also seems to fire when textbox is clicked on and typed into.
$scope.$watch('testObj', function(){
console.log('this is working?');
}, true);
if you want to catch the change in the model binded to change event externally.. the only option we have is to use $watch..
here it looks like you have added $watch to wrong varible as "testObj" is not binded as the model to the input field.
please see video to understand difference between ng-change and $watch
https://egghead.io/lessons/angularjs-using-the-ngchange-directive-in-angular
You can use slideEnded event as described here: to be notified about model changes.
I am using knockout.js. I created a view model say testViewModel with only 1 observable property testProperty.
function testViewModel()
{
var self = this;
self.testProperty = ko.observable("Initial");
}
than i created a span in which the changed value of testProperty is reflected and a input text field by which we can change the testProperty value.
<span data-bind="text: testProperty"></span><br />
<input type="text" data-bind="value: testProperty" />
I created an Example Fiddle.It seems that the observable property value is updated when the focusout event is executed on the input text field.
Now my question is that can we change the observable property value update event from focusout to something else. I created a save button also. Is there any way to update the observable property value only on save button press.
I am trying to create an application in which a user can create and save its profile and can edit the saved profile.I am using the same observable properties in create and edit form and these properties are observable. So when user edit its profile the ui should not
be updated until user press the save button. This is my goal. Please help me to solve this issue ?
I would suggest have testProperty and testProperty_temp. Bind the input to temp and when the button is clicked, set testProperty to the testProperty_temp
function testViewModel()
{
var self = this;
self.testProperty = ko.observable("Initial");
self.testProperty_temp = ko.obserable("");
self.save = function() { self.testProperty(self.testProperty_temp()); }
}
Hope this helps
Another means, along the same lines of what Matt Burland suggested:
http://jsfiddle.net/mori57/PQxJC/
Basically, wrap your input and button in a form, and bind the form to submit: which is handled by a method on your ViewModel. See the comments I've made inline, but here it is for people who don't want to go out to jsFiddle:
<span data-bind="text: testProperty"></span><br />
<!-- wrap the input and button in a form and
data-bind to submit, with a reference
to a handler on your viewmodel -->
<form data-bind="submit: updateProfile">
<!-- this must be bound to your shadow value -->
<input type="text" data-bind="value: _tmpTestProperty" />
<button type="submit">save</button>
</form>
and in your javascript
function testViewModel()
{
var self = this;
self.testProperty = ko.observable("Initial");
// Create the "shadow" property
// and prepopulate it with testProperty's value
self._tmpTestProperty = ko.observable(self.testProperty());
// Create our form handler
self.updateProfile = function(val){
// set the testProperty value to the
// value of the shadow property
self.testProperty(self._tmpTestProperty());
};
}
ko.applyBindings(new testViewModel());
In this way, your value doesn't change when you lose focus on the text input box, but is only updated when you submit the form.
Your simplest approach would be to have a shadow property for each of your properties. So you bind one to your text boxes and only copy the value to the other property, the one bound to the other UI elements, when save is clicked.
See here: http://jsbin.com/aguyud/5/edit
An easier way using two models and $.extend to copy from one to the other:
http://jsbin.com/aguyud/7/edit
Update, actually scratch that, that doesn't seem to work. I tried this instead:
http://jsbin.com/aguyud/22/edit
which works the first time, but after copying the model with $.extend it seem it's copied all the bindings too, so it only works once!