JSfiddle code at the bottom
My problem: If an <input> field has whitespace in it and you "clear" the value with angular by setting its scope value to an empty string, it leaves the whitespace in the input field.
The reason: I understand why it is doing it, as the angular digest doesn't see a change, since it already has the scope variable empty due to trimmed whitespace via ng-trim.
My question: Is there a proper way to make sure the input field gets blanked out? I know of multiple solutions, but all of them are hacks or wouldn't work.
Set the scope value to null, and then to blank after a $timeout. But this could cause problems due to the code expecting only strings in the scope value.
Set the element to ng-trim, but I like having the value automatically trimmed
Empty the input field with jquery (or directly setting the element's value). This is probably the solution I am going to end up going with (a function that clears the input and blanks the scope variable at the same time), but I'm hoping there is something not quite so hacky.
jsfiddle: https://jsfiddle.net/0kf84g5o/3/
HTML
<div ng-app=MyApp>
<div ng-controller="TestCtl">
Press "tabs and spaces", add spaces and/or tabs, and then press "blank out'<br>
<input ng-model=TestInput id=TestInput>
<input type=button value="abc" ng-click="ChangeTestValue('abc')">
<input type=button value="Tabs and spaces"ng-click="ChangeTestValue('\t \t')">
<input type=button value="Blank out" ng-click="ChangeTestValue('')">
<input type=button value="Null out" ng-click="ChangeTestValue(null);">
<pre>
Angular Value: --{{TestInput}}--
JSONified Angular Value: --{{TestInputJSON}}--
Actual input value JSONified: --{{TestInputActualJSON}}--
</pre>
</div>
</div>
Javascript
var MyApp=angular.module('MyApp', []);
MyApp.controller('TestCtl', function($scope, $timeout) {
//Update the value programatically
$scope.TestInput='Start text';
$scope.ChangeTestValue=function(Str) {
$scope.TestInput=Str;
};
//Update TestInputJSON
$scope.$watch('TestInput', function(NewVal) { //When angular values changes
scope.TestInputJSON=JSON.stringify(NewVal);
});
//Update TestInputActualJSON
$scope.$watch('TestInput', function(NewVal) { //When angular value changes
$timeout(UpdateTestInputActualJSON, 1); //Wait for 1ms to update so the new value is alread set
});
$('#TestInput').on('keyup paste', UpdateTestInputActualJSON); //On a jquery event
function UpdateTestInputActualJSON(e) //Do the actual update of TestInputActualJSON
{
$scope.TestInputActualJSON=JSON.stringify($('#TestInput').val());
if(e) //Call angular digest if coming from jQuery
$scope.$apply();
}
});
Related
I have an
<input id="myTextBox" data-dojo-type="dijit/form/TextBox" data-dojo-props="value: at(model, myValue)" />
When I try to copy the value from model.myValue to another input (e.g. by
window.setInterval(
function() { document.getElementById("theOtherInput").value = model.myValue; }, 1000);
I notice, that the value of myTextBox isn't synchronized with model.myValue until the <input> of myTextBox lost focus. I.e. - theOtherInput won't be updated unless I leave the input field myTextBox.
How to force dojo to synchronize the input with the bound variable with every keystroke? I thought that this should have been the default behavior or at least it should be possible with little effort, but I don't find the right attribute to do it. Any ideas?
The main problem for me is, when I submit the form by the enter key, the model.myValue has still the value before the input myTextBox got the focus. (and I don't want a hack with setInterval - I just want to have dojo doing its job of synchronizing the input with the model)
The closest you can get is setting intermediateChanges property to true and attach an onChange event. Something like this:
<input id="myTextBox" data-dojo-type="dijit/form/TextBox"
data-dojo-props="intermediateChanges: true"
data-dojo-attach-event="onChange: _myOnChange"
data-dojo-props="value: at(model, myValue)" />
Now, inside your widget, the _myOnChange function will run with each valuable keystroke or if the content is changed.
_myOnChange: function(newValue){
console.log(newValue);
document.getElementById("theOtherInput").value = newValue;
}
I have a simple typeahead for a list of currencies. When I start typing and I select the desired value (or hit TAB on that), the desired value is selected - until this point everything works as desired.
However, if I type the entire word and click outside the input instead of selecting the value (onblur event), then even if the value inside my input matches the filter value, the selected scope variable doesn't update, so my input is invalid. What I'm trying to do is to overwrite the selected value during onblur event.
Example: If I type EUR without hitting TAB or selecting the EUR value from the typeahead dropdown and then click outside the input, the EUR text stays inside the input, but selected value is undefined. I want the selected value to hold EUR instead of undefined. I used $viewValue to send the input value during onblur event.
The HTML:
<input type="text" ng-model="selected" typeahead-editable="false" typeahead="currency for currency in currencies | filter:$viewValue" ng-blur="selectCurrency($viewValue)" />
<div>Selected: {{selected}}</div>
The JavaScipt:
angular.module('myApp', ['ui.bootstrap'])
.controller("mainCtrl", function ($scope) {
$scope.selected = '';
$scope.currencies = ['EUR', 'GBP', 'USD'];
$scope.selectCurrency = function(test) {
console.log(test); //outputs undefined instead of EUR
//if (checkIfCurrencyExists(test, $scope.currencies)) { - will do the checks later
$scope.selected = test;
//}
};
});
In the JsFiddle below you can see the same scenario, except it has US states instead of currencies. Try to type in Alabama then left click outside the input (don't TAB and don't select the state), you'll see that the selected scope variable stays empty
JsFiddle link here.
Found another solution - setting both typeahead-select-on-exact and typeahead-select-on-blur attributes to true:
<input typeahead-select-on-exact="true" typeahead-select-on-blur="true" uib-typeahead=...
Typeahead-select-on-exact makes the exactly matching item automatically highlighted in the list, and typeahead-select-on-blur makes the higlighted item selected on blur.
If you want to select the first result from the typeahead list on blur, then you can set typeahead-select-on-blur="true" in your input field as given in the doc.
typeahead-select-on-blur (Default: false) - On blur, select the
currently highlighted match.
Found an answer myself at the time, but forgot to answer my question here.
Added this to the directive:
data-ng-blur="blur($event)"
And this is the function:
$scope.blur = function(e) {
var inputCurrency = e.target.value.toUpperCase();
angular.forEach($scope.currencies, function(currency) {
if (currency === inputCurrency) {
$scope.field = currency;
}
});
};
I spend some time searching for similar question and made a lot of testing untill I got it working. I can see that in answers there is a solution but I try to summarize it so it could be a bit more clear.
In typeahead part include:
<input type="text" ng-model="selected" typeahead-editable="false" typeahead="currency for currency in currencies | filter:$viewValue" ng-blur="checkSelectedValue()" typeahead-select-on-blur="true" />
First part includes validation function of your scope value (you don't need to pass the value as it's the $scope.selected and you can use it in your controller): ng-blur="checkSelectedValue()".
Thus include in your controller:
$scope.checkSelectedValue = function() {
if (code that check if $scope.selected in range of allowed values) {
$scope.inputValid=true; //you can use this scope or write code that run when selected a correct value
} else {
$scope.inputValid=false;
}};
Second part: typeahead-select-on-blur="true"// it's necessary since it first will make $scope.selected=selected value from dropdown (complete word) but also a bit weird, but important to know that after typeahead will selected your value it will run ng-blur= "checkSelectedValue()" directive in the end so there it will always check for validation and will set your $scope.inputValid=true or false depending on $scope.selected value.
I'm running into a strange issue in Firefox that I hope someone can explain to me. I have an AngularJS controller with a method that is tied to ng-change on a variety of input controls in a form, including one that is marked as a number input. The logic of this method is that if any one of the bound scope variables is set properly, to set another scope variable to true. This is basically an attempt at form validation where any one (or more) of the inputs is required.
Example:
app.controller('test', function($scope) {
$scope.num = 0;
$scope.name = "";
$scope.valid = false;
$scope.inputChange = function() {
console.log('Input changed');
$scope.valid = ($scope.num > 0) || ($scope.name.length > 0);
}
});
And form:
<form name="numberTest" ng-app="myApp" ng-controller="test">
<input ng-model="name" name="name" type="text" ng-change="inputChange()"/>
<input type="number" ng-model="num" name="n" id="n" ng-change="inputChange()"/>
<input type="button" value="Go" ng-disabled="!valid"/>
</form>
This all works fine in Chrome, but in Firefox this ng-change handler is fired when non-numeric text is entered in the numeric input and the textbox itself does get this bogus data in it although the model is not updated. This leads to a confusing state where there is invalid data in the num textbox that is not bound to the AngularJS model but the user can click the button. Chrome does not present this problem as it does not render the non-numeric data in the input control.
How can I detect (and handle) this scenario? The input control is displaying text that is invalid and not bound to the binding model.
I am certainly open to alternative implementations to achieve this same effect. AngularJS version is 1.3.0.
Example plunker to run in Firefox to see the "bad" behavior
I ended up discovering the $valid attribute of these number inputs, and that seemingly satisfies my needs:
Returns true if empty
Returns false if non-numeric data is in the control
So, my updated button:
<input type="button" value="Go" ng-disabled="!valid || !numberTest.n.$valid"/>
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.
Using jQuery, I change the value of an input text field through some process. After the process is done, I need to capture this change and apply it to another process. My problem is that I can't seem to capture this change and assign it to a variable. I know the changes are happening because the DOM is getting updated. Furthermore, this variable assignment works in IE, but not for the other browsers I tested.
Below is a snippet to prove my point (and you can see this online here: http://jsfiddle.net/xMwAE/).
<form>
<input type="hidden" name="my_hidden" value="Hidden Field" />
<input type="text" name="my_text" value="Text Field" />
</form>
$().ready(function() {
$('input[name=my_hidden]').val('Hello Hidden Field');
$('input[name=my_text]').val('Hello Text Field');
// Display
var temp = $('form').html();
// Though the DOM is updated with the new values. The variable temp
// does not capture the changes to the input text field, but captures
// the change in the hidden field. When in IE, temp captures the
// changes in both fields.
alert(temp);
});
Obviously, I need consistent behavior across browsers. Any ideas what's going on?
I don't get any trusted idea what happens, but somehow there should be a difference between setting the value as a member (input.value) or setting the value as a attribute-node.
This works for me :
$('input[name=my_text]').each(function()
{ this.setAttribute('value','Hello Text Field');});
I guess its a bug in innerHTML, see bugzilla: https://bugzilla.mozilla.org/show_bug.cgi?id=535992
Alternatively, you can store the values of your fields into array and use however you like like this:
var data = [];
$('form :input').each(function(){
data.push(this.value);
});
Now you can check for values like this:
alert(data[0]);
alert(data[1]);