AngularJS - Pause binding of input field while focused - angularjs

I have a data object that looks like this:
$scope.data = { value1: 'anyValue', value2: 'anyValue'};
This data object will be updated via polling every second.
In the view I'm showing the data in input fields like:
<input type="number" ng-model="data.value1"/>
<input type="number" ng-model="data.value2"/>
The user should be able to focus one of the input fields and enter a value. Now this is not possible, because every change that is made in the field will be overwritten, when the data object gets updated.
I don't want to pause the whole polling process, because the other input field should still show its updated value.
What is the best way to pause only the binding of the focused input field, while it is focused?

I suggest you do the following:
<input type="number" ng-model="data.value1" ng-focus="onFocus('value1')" ng-blur="onBlur('value1')"/>
<input type="number" ng-model="data.value2" ng-focus="onFocus('value2')" ng-blur="onBlur('value2')"/>
In your controller, something like:
$scope.onFocus = function(key) {
$scope.preventChange = key;
};
$scope.onBlur = function(key) {
$scope.preventChange = null;
};
And then whenever you do your polling and updating, check if the data key you are trying to update is the one in $scope.preventChange, and if so - don't change it.

Related

How can I change an ng-select choice in response to a change in my model?

I have an input field and an ng-select next to each other. Both are backing for the same data. As there are a large number of items in the select I can use the input field if I know the value that's needed.
But when I change the value of the input field the ng-select doesn't change until I do an update of the data in the database and retrieve data again.
When I change the value in the ng-select the value in the input field changes immediately.
Is there a way that I can get the ng-select to track changes to the underlying model and respond?
Here's the code that I have:
<div class="p0r2 textAlignCenter verticalAlignTop">
<textarea class="h1r5 pl0r3 lh1r5 resizeNone w2r"
ng-change="phs.phrasesStatus = Status.Dirty; row.statusId = Status.Dirty"
ng-model="row.categoryId"
maxlength="3" size="3"
ng-required="true"></textarea>
</div>
<div class="p0r2 textAlignCenter verticalAlignTop"
ng-if="!phs.show">
<select class="select"
convert-to-number
ng-change="phs.phrasesStatus = Status.Dirty; row.statusId = Status.Dirty"
ng-options="option.id as option.name for option in phs.phraseCategory.data"
ng-model="row.categoryId"></select>
</div>
Here's the type of data with Typescript:
interface IEnumServiceGetData {
data: IMapIdName[];
dataPlus: IMapIdName[];
dataMap: {};
dataMapPlus: {};
name: any;
}
interface IMapIdName {
id: number; name: string
}
You are probably using the numeric version for the id. WHen you choose a value in the input, it will be stored as a string. If the select id is a number, it will not match. Use the string version for the select ids, like this:
$scope.options = [{id:"1", name:"A"},{id:"2", name:"b"},{id:"3", name:"c"}]

ng-model - getting name and value of input box

I have an update function and a number of input boxes. Each input has an ng-blur attached to it so that the update function is called whenever the cursor leaves the box.
$scope.update = function(data) {
console.log(data); //outputs value in the textbox
//how can I output/access the key?
}
The input for name look like this:
<input type="text" ng-model="user.name" ng-blur="update(user.name)"/>
As I need to be able to post a JSON object in the form {"name" : "bob smith"} what's a good way of generating the "key" of the object bearing in mind that it will differ depending on the input box that's being used at the time?
EDIT ↓
I have made this jsfiddle to illustrate a way to do it more cleanly & that would scale more easily: http://jsfiddle.net/kuzyn/k5bh0fq4/5/
EDIT ↑
Why not simply pass a second string argument? It's not a fancy way to do it but it would work:
<input type="text" ng-model="user.name" ng-blur="update(user.name, 'name')"/>
And
$scope.update = function(data, key) {
console.log(key, data);
}
It might be a little more work but it is much more scalable. You could make use of the ng-form and naming your form inputs. By naming your form and inputs, you are creating a form reference on your scope via $scope[form-name]. Each named input within that form then sets an input reference via $scope[form-name][input-name].
I'm coding this in coffeescript (to preserve my sanity, sorry)
form
<form name="myForm">
<input name="name" ng-model="user.name" ng-blur="update(user)"/>
<input name="email" ng-model="user.email" ng-blur="update(user)"/>
<input name="other" ng-model="user.other" ng-blur="update(user)"/>
</form>
update & save func
# key is what changed in case you need to do something special on the put call to server
$scope.save = (data, key)->
# pseudo-code
$scope.update = (data)->
for name, input of $scope.myForm
if input?.$dirty
$scope.save data, name
break
docs - https://docs.angularjs.org/guide/forms
codepen - http://codepen.io/jusopi/pen/LGpVGM?editors=101

can i paste text input value on-keyup in angular?

using angularJS 1.5.0-beta2
I'm wondering if its possible to paste the text input value using onkeyup.
for example:
<input type="text" id="foo" on-keyup="doit(<text-input-value>)" />
so in the doit function i need to paste the value of the text input.
any ideas?
If you just want the one key that was pressed then use String.fromCharCode() to find which key it is from the event keyCode.
$scope.showKey = function(event){
var pressedKey = String.fromCharCode(event.keyCode);
alert(pressedKey);
}
If you want to get all of the contents of the text input it would be better to use ng-model and ng-change together.
<input type="text" id="foo" ng-model="myInputValue" ng-change="doSomething()"></input>
var doSomething = function(){
alert($scope.myInputValue);
};

Post full form data to a service in Angular

I have a form that contains a lot of fields and I want to post all the form fields to a service using a post method. But I would like to send the whole form object and not to write one property by one. If I try to post the object that contains all my fields $scope.formData it also contains all the angular stuff inside like errors. What I need is a collection of field names and values. How can I achieve this with minimum coding?
Edit:
I ended up writing my own function:
function getAngularFormFields(form) {
var dictionary = { form: {} };
for (var key in form) {
if (form.hasOwnProperty(key) && !key.indexOf('$') == 0) {
dictionary.form[key] = form[key].$modelValue;
}
}
return dictionary;
}
Normally if you need to post a form you could just use the default method provided by your browser. This will send the form data, via POST, to your URL.
<form action="yourUrlHere" method="POST">
First name: <input type="text" name="fname">
Last name: <input type="text" name="lname">
<input type="submit" value="Submit">
</form>

How can I make angularjs ngChange handler be called only when user finishes typing

I have an input field, where I want to apply the variant of ngChange.
The input field is sort of binding with an ajax call, when user changes the input, the server side will process the data, however, I don't wanna make the call too often.
Say the user wanna input a really string, I want the call be made only after user finishes the word he is about to type.
Nevertheless, I don't wanna use event such as blur. What would be a better way to implement this, rather than setTimeout?
Use ng-model-options in Angular > 1.3
<input type="text"
ng-model="vm.searchTerm"
ng-change="vm.search(vm.searchTerm)"
ng-model-options="{debounce: 750}" />
Without ng-model-options -- In markup:
<input ng-change="inputChanged()">
In your backing controller/scope
var inputChangedPromise;
$scope.inputChanged = function(){
if(inputChangedPromise){
$timeout.cancel(inputChangedPromise);
}
inputChangedPromise = $timeout(taskToDo,1000);
}
Then your taskToDo will only run after 1000ms of no changes.
As of Angular 1.3, you could use Angular ng-model-options directive
<input ng-change="inputChanged()" ng-model-options="{debounce:1000}">
Source: https://stackoverflow.com/a/26356084/1397994
Write your own directive- this will only run the commands on myText based on the conditions you set
<input my-change-directive type="text ng-model="myText" />
.directive('myChangeDirective',function() {
return {
require : 'ngModel',
link : function($scope,$element,$attrs) {
var stringTest = function(_string) {
//test string here, return true
//if you want to process it
}
$element.bind('change',function(e) {
if(stringTest($attrs.ngModel) === true) {
//make ajax call here
//run $scope.$apply() in ajax callback if scope is changed
}
});
}
}
})

Resources