adding watch for an editable row in angularjs - angularjs

I am using xeditable for editing a table row in angular js. HTML Code is shown below.
<tr ng-repeat="expense in viewModel.expenses">
<td>{{expense.eid}}</td>
<td><span editable-text="expense.billAmt" e-ng-model="editForm.billAmt" e-name="billAmt" e-form="rowform">{{expense.billAmt}}</span></td>
<td><span ng-show="!rowform.$visible">{{expense.split}}</span><input type="text" ng-show="rowform.$visible" class="form-control input-sm" e-ng-model="editForm.split" ng-disabled="true" /></td>
I want to update the 'split' value in last column when the value in 'billAmt' changes. So I add a watch in angularjs but is not updating.
$scope.$watch('editForm.billAmt',function(newValue,oldValue) {
$scope.editForm.split=newValue/$scope.viewModel.members.length;
});
Is there any other way to add a watch while using xeditable?? How can I solve this?

I'd refrain from using $scope.$watch() and turn to a more efficient solution. You can use the e-ng-change directive to fire a function computing new value of $scope.editForm.split every time the billAmt value changes. It would look like this:
<tr ng-repeat="expense in viewModel.expenses">
<td>{{expense.eid}}</td>
<td><span editable-text="expense.billAmt" e-ng-model="editForm.billAmt" e-name="billAmt" e-form="rowform" e-ng-change="checkSplit();">{{expense.billAmt}}</span></td>
<td><span ng-show="!rowform.$visible">{{expense.split}}</span><input type="text" ng-show="rowform.$visible" class="form-control input-sm" e-ng-model="editForm.split" ng-disabled="true" /></td>
And in your controller add function checkSplit():
$scope.checkSplit = function(){
$scope.editForm.split = $scope.editForm.billAmt / $scope.viewModel.members.length;
}
The checkSplit() function is invoked explicitly in a response to a event of value change, whereas $scope.$watch() handler runs on every digest cycle, so you can technically save some performance too.

Related

Values are duplicated into all input field which is created using the ng-repeat and ng-model

I am using the ng-repeat to create the input fields dynamically, everything seems to be working fine and the input fields are created but due to some reason when I enter some value into that created input field then due to two-way data binding the value is entered simultaneously in all the text fields that were created.
As per my knowledge, I am assigning the different ng-model to each of the created fields so I am not sure why the values are being copied. When I try to print the values which are assigned to the input field just above the field then I see the id is different wanted to know why all the fields are taking the same value and also how can I prevent it.
HTML Code:
<tr>
<td ng-repeat="extension in ExtensionList">
<!-- Here the value displayed are different -->
{{ formdata.extension.ExtensionVlaues }}
<input type="text" class="form-control" id="extension.ExtensionVlaues" ng-model="formdata.extension.ExtensionVlaues">
</td>
</tr>
Here is the screenshot from the front-end:
Here is the example of my ExtensionList: {"Field1":"","Field2":"","Field3":1,"ExtensionVlaues":2}
As per my knowledge, the given ng-model is different but still not working. Can anyone please help me with this? I tried few things like ng-model="formdata.extension[ExtensionVlaues]" but still no luck.
I tried to assign ng-model like this but it is not working:
ng-model="formdata.extension[ExtensionVlaues]"
Based on the below answer I tried 2 different things it but it's not working and getting the same issue. Please let me know how can I resolve this:
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata.extension.key">
</td>
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata.extension.ExtensionVlaues">
</td>
You are trying to use ExtensionList as an array. You need to use it as an object with ng-repeat:
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata[extension][key]">
</td>
<td ng-repeat="(key, extension) in ExtensionList">
<input type="text" ng-model="formdata[extension][ExtensionVlaues]">
</td>
Just incase anyone else also struck at this issue:
<span ng-repeat="(key, extension) in ExtensionList" class="form-inline">
<br/>
<span>
{{ extension.NameSpace + ":" + extension.LocalName }}
</span> 
<input type="text" class="form-control" id="extension.ExtensionVlaues" ng-model="ExtensionList.extension[key].FreeText" ng-blur="ExtensionText(ExtensionList.extension[key].FreeText, extension.ExtensionVlaues)">
</span>

Updating input values filled out by ng-repeat | Angular js

I have to update the value of multiple Inputs using ng-repeat. i usually get the value with JQuery $(class/id).val() and get its value. but now i have no idea how to access the input values since i only have one id for each. (i have like 20 input in the table)
View:
<tr ng-repeat="i in list">
<td><input list="itemNames" class="item_name" ng-model="i.item_name" value="{{i.item_name}}" type="text"/></td>
<datalist id="itemNames">
<option ng-repeat="ii in list" class="idI" ng-model="ii.idI" data-item="{{ii.idI}}" value="{{ii.item_name}} {{ii.idI}}">
</datalist>
<td><input class="quantity" ng-model="i.quantity" value="{{i.quantity}}" type="number"/></td>
<td><input class="price" ng-model="i.price" value="{{i.price}}" type="number"/></td>
<tr>
<td ng-click="updateAll()">UPDATE</td>
</tr>
</tr>
I expect to store all values in an arrays, but what i got is only values of the first row.
JS:
$scope.updateAll=function(){
// getting vallues
var item_name=$(".item_name").val();
var quantity=$(".quantity").val();
var price=$(".price").val();
}
I think your list is a scope variable. So, in controller its defined as $scope.list. You need not to think about id as you are using angular code, angular framework will do it for you.
As you used the two way data binding with ng-model, so any change to the bind variable will be immediately visible to controller and html view.
The use of ng-model ensures the immediate update to the $scope.list variable.
For example, if you add any text for "item_name" in the control index 0 from html view, the variable $scope.list[0].item_name will be automatically updated, also the change in $scope.list[0].item_name = "Some name" in controller will be automatically reflected in the view.
So, your given code can be re-written as following:
<tr ng-repeat="i in list">
<td><input list="itemNames_{{$index}}" class="item_name" id="txt_name_{{$index}}" ng-model="selectedValue" ng-change = "getSelectedId(selectedValue, $index)" type="text"/></td>
<datalist id="itemNames_{{$index}}">
<option ng-repeat="ii in list" class="idI" ng-model="ii.idI" data-item="{{ii.idI}}" value="{{ii.item_name}} {{ii.idI}}">
</datalist>
<td><input class="quantity" ng-model="i.quantity" value="{{i.quantity}}" type="number"/></td>
<td><input class="price" ng-model="i.price" value="{{i.price}}" type="number"/></td>
<tr>
<td ng-click="updateAll()">UPDATE</td>
</tr>
The javascript method can be written as:
var getSelectedId = function(selectedValue, index) {
var val = document.getElementById('txt_name_' + index).value;
var text = $('#itemNames_' + index).find('option[value="' + val + '"]').attr('data-item');
alert(text);
}

Changing single cell color with ngClass

I'm having a hard time here with ngClass as I'm new to angular. I've got a table set up that generates rows dynamically from a database using ng-repeat, with span and input elements that hide/show based on editing/not editing the cell (imagine microsoft excel).
<tr>
<th class="row_head">Row Title</th>
<td ng-click="edit = true" ng-repeat="item1 in JSONobject | orderBy: '_id'" >
<span ng-hide="edit">{{ item1.key.value1 }}</span>
<input ng-show="edit" class="editing-cell" ng-model="item1.key.value1" ng-blur="edit = false; " ng-enter="saveData(item1._id, item1.key); edit = false" type="text" />
</td>
</tr>
<tr>
<th class="row_head">Row Title</th>
<td ng-click="edit = true" ng-repeat="item2 in JSONobject | orderBy: '_id'" >
<span ng-hide="edit">{{ item2.key.value2 }}</span>
<input ng-show="edit" class="editing-cell" ng-model="item2.key.value2" ng-blur="edit = false; " ng-enter="saveData(item2._id, item2.key); edit = false" type="text" />
</td>
</tr>
and so on.
I want to set it so on blur (data not saved) the cell turns red, and alternatively on save - turns green.
The issue i'm running into with ngClass is if i just go with:
ng-class="{'saved': saved, 'notSaved': notSaved}"
It changes the background color of EVERY cell, rather than just the cell edited.
I do not have this issue with ng-hide and ng-show, even though they appear to be a similar scenario with changing the boolean value of 'edit'. They still stick to their specific cell.
Any help would be appreciated.
You should look into how form styling works.
The following classes are added to, or removed from, input fields:
ng-untouched The field has not been touched yet
ng-touched The field has been touched
ng-pristine The field has not been modified yet
ng-dirty The field has been modified
ng-valid The field content is valid
ng-invalid The field content is not valid
ng-valid-key One key for each validation. Example: ng-valid-required, useful when there are more than one thing that must be validated
ng-invalid-key Example: ng-invalid-required
The following classes are added to, or removed from, forms:
ng-pristine No fields has not been modified yet
ng-dirty One or more fields has been modified
ng-valid The form content is valid
ng-invalid The form content is not valid
ng-valid-key One key for each validation. Example: ng-valid-required, useful when there are more than one thing that must be validated
ng-invalid-key Example: ng-invalid-required
The classes are removed if the value they represent is false.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<style>
form.ng-pristine {
background-color:lightblue;
}
form.ng-dirty {
background-color:pink;
}
</style>
<body ng-app="">
<form name="myForm">
<p>Try writing in the input field:</p>
<input name="myName" ng-model="myName" required>
<p>The form gets a "ng-dirty" class when the form has been modified, and will therefore turn pink.</p>
</form>
</body>
</html>
My issue was not knowing enough about custom directives. I've got it figured out now with
.directive('isSaved', function(){
return {
link: function(scope, elem, attr) {
scope.notSaved = function(){
attr.$set('class', 'notSaved');
};
scope.saved = function(){
attr.$set('class', 'saved');
};
}
};
});

AngularJS to replace textbox value with expression with a function call

I have an Angular form where ng-repeat is used to create several TDs and each TD element holds a textbox whose value I want to modify using a function call with parameter. I hold values in an array and want to pick a value from there and put in textbox element.
<div ng-controller="MyController" ng-form id="myForm" name="myForm">
<table>
<tr>
<td ng-repeat="myObject in arrayOfObjects">
<input type="text" ng-???="{{ myFunctonCall(myObject.Property) }}" />
</td>
</tr>
</table>
</div>
Is there a standard ng directive or it can be achieved using formatters, parsers?
You can use ng-init to initialize a scope value inside each child scope of ng-repeat. Those values won't be shared with your parent controller, where arrayOfObjects is defined.
https://docs.angularjs.org/api/ng/directive/ngInit
(as said in the doc, do not use too much ngInit)
<div ng-controller="MyController" ng-form id="myForm" name="myForm">
<table>
<tr>
<td ng-repeat="object in arrayOfObjects">
<input type="text"
ng-init="value = myFunctionCall(object.Property);"
ng-model="value" />
</td>
</tr>
</table>
</div>
as #Deblaton Jean-Philippe said you can use ng-model to read the data
<input type="text" ng-model="myinitialvalue" />
then process it in the controller the way you want:
$scope.$watch('myinitialvalue' function(newval, oldval){
//newval is equal to value of myinitialvalue
//here we modify it and assign to myvar, here for example we just add 'abc' to it
$scope.myvar = newval + 'abc';
});
and angular template syntax {{myvar}} to show it in textarea or in some other place if the page:
<textarea>{{myvar}}</textarea>

Angular binding to object field

I'm using angular with ng-repeat like that:
<tr ng-repeat="(fieldName, fieldValue) in publication">
<td>
<input type="text" ng-value="publication[fieldName]">
</td>
</tr>
But binding doesn't work - so after change I have still old values in publication[fieldName]. How can I achieve binding?
It should be ng-model instead of ng-value if you want a data binding.

Resources