Angularjs : update variable using {{key}} inside ng-repeat - angularjs

I set up an example to demonstrate my problem :
Here is the associated fiddle link : http://jsfiddle.net/kqw6N/
<div ng-app>
<span ng-init="myvar = {myattribute:'init'}">{{myvar.myattribute}}</span>
<table ng-init="myarray = {'key1': 'value1', 'key2': 'value2'}"><tbody>
<tr>
<td ng-repeat="(key, value) in myarray" ng-click="myvar.myattribute='{{key}}'">
{{value}}
<span ng-click="myvar.myattribute='ok'">test</span>
</td>
</tr>
</tbody></table>
</div>
I would like to update myvar.myattribute while I click on the td inside ng-repeat. It works if I use a constant, but not if I use {{key}}.

You don't need to embrace your key variable. You can access it as follows:
<td ng-repeat="(key, value) in myarray" ng-click="myvar.myattribute=key">
It's already in scope, so it will be found by angular.

Related

Angularjs ng-repeat array value

myCtrl.Data.summary.account
if i print above model i get the output like below
["1","2","3","4","5"]
i want to use ng-repeat on this value, how to achive this?
I tried following code snippet using ng-repeat but it's not printing anything
<td ng-repeat="data in myCtrl.Data.summary.account">
<tr>{{data}}</tr>
</td>
What mistake i made here? can anyone please point out this issue. How to fix this?
it is ng-repeat not ng-repet
<td ng-repeat="data in myCtrl.Data.summary.account">
<tr>{{data}}</tr>
</td>
1) Use ng-repeat instead of ng-repet
2) If you are using controllerAs syntax check if myCtrl is correct controller name in controllerAs value
3) If you are using $scope then you should create $scope.myCtrl.Data.summary.account in controller
You should place the value in the columns and repeat for the rows. Your code should be in this format:
<tr ng-repeat="data in myCtrl.Data.summary.account">
<td>{{data}}</td>
</tr>
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.arr = ["1","2","3","4","5"]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<table>
<tr>
<td ng-repeat="data in arr">
<table>
<tr>
<td >{{data}}
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
cant use directly <tr>inside <td> . you need to create a table and add it there
<td ng-repeat="data in myCtrl.Data.summary.account">
<table>
<tr>
<td>{{data}}
</td>
</tr>
</table>
</td>

AngularJS - no two way binding for key-value object

Just for note, I know nothing about angularJS, I worked with knockoutJS before and when it comes to angular I am just making assumptions.
I have code like this:
angular.module("umbraco").controller("recallCtrl",
function ($scope, $routeParams) {
$scope.dcList = {
key: "value",
abc: "aaaa",
prop: "tadaa!"
}
});
and markup as follows:
<div ng-controller="recallCtrl">
<table class="table table-sm">
<thead>
<tr>
<td></td>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tr ng-repeat="(key, value) in dcList">
<td>
</td>
<td>
<input ng-model="key" />
</td>
<td>
<input ng-model="value"/>
</td>
</tr>
</table>
<pre>{{dcList | json}}</pre>
</div>
So shouldn't output of dcList in the end of html change it's values when I edit corresponding inputs which as I assume are bound to object?
If I am doing something wrong, please advise. I want to create object and be able to change its keys and values.
The reason your current code isn't working is because the "key" and "value" variables are scoped within the ng-repeat, and no longer refer directly to the original object.
Keeping the "values" attached is easy, just use dcList[key] instead of value. Adding new keys takes a bit more work; here I've attached an ng-blur to each "key" field which will init a new key when the field blurs. (ng-change would create a new field on every keystroke, which isn't what you want.) Note that when you start typing a new key, its value appears to disappear -- this is because the dcList[key] refers to the new key name immediately. This would be somewhat confusing in a real UI, of course; you'd probably want to code different behavior into the createNewKey function (such copying the old value into the new key, or deleting the original key).
function recallCtrl($scope) {
$scope.dcList = {
key: "value",
abc: "aaaa",
prop: "tadaa!"
}
$scope.createNewKey = function(k) {
$scope.dcList[k]="";
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="recallCtrl">
<table class="table table-sm">
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tr ng-repeat="(key, value) in dcList">
<td>
<input ng-model="key" ng-blur="createNewKey(key)"/>
</td>
<td>
<input ng-model="dcList[key]"/>
</td>
</tr>
</table>
<pre>{{dcList | json}}</pre>
</div>
please test this code, change in the value corresponding to the key,
angular.module('app', [])
.controller('Controller', function($scope) {
$scope.dcList = {
key: "value",
abc: "aaaa",
prop: "tadaa!"
}
})
<!DOCTYPE html>
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
</head>
<body ng-app="app">
<div ng-controller="Controller">
<table class="table table-sm">
<thead>
<tr>
<td></td>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tr ng-repeat="(key, value) in dcList">
<td>
</td>
<td>
<input ng-model="key" disabled/>
</td>
<td>
<input ng-model="dcList[key]" />
</td>
</tr>
</table>
<pre>{{dcList | json}}</pre>
</div>
</body>
</html>
Here is the plunker

How to avoid ng-init in angular?

I want to show message when ng-repeat collection is empty i.e.:
<div ng-init="filteredArray=(array|filter:{...})">
<h1 ng-if="!filteredArray.length">Empty array</h1>
<table ng-if="filteredArray.length">
<tr ng-repeat="element in filteredArray">
<td>{{element}}</td>
</tr>
</table>
</div>
The problem is that ng-init will not watch for modification of the source array. Any hint how to do it properly?
You can just create the filtered variable in the ng-repeat, and use that one:
<div>
<h1 ng-if="!filteredArray.length">Empty array</h1>
<table ng-if="filteredArray.length">
<!-- here angular assigns the filtered array to the 'filteredArray' variable,
which then can be used -->
<tr ng-repeat="element in filteredArray=(array|filter:{...})">
<td>{{element}}</td>
</tr>
</table>
</div>
See also this jsfiddle
EDIT
If you don't like the ugly expression, you can also do something like this:
function myController ($scope, $filter) {
$scope.$watch("theFilter", function (val) {
$scope.filteredArray = $filter("filter")($scope.array, val);
});
}
And in your html:
<tr ng-repeat="element in filteredArray">
..
</tr>
Check in this jsfiddle
Check ng-repeats $last to show your message like below
<div ng-repeat="n in data track by $index">
<h1 ng-if="$last">Empty array</h1>
</div>
In your case you can have a variable at the table level and then set it to $last,when it'll be true your message will show like below
<body ng-app="app" ng-controller="ctrl">
<div ng-init='counter=false'>
<h1 ng-if='counter'>Empty array</h1>
<table ng-if="myData.length">
<tbody>
<tr ng-repeat="element in myData track by $index" ng-init="counter=$last">
<td>{{element}}
<ng-if ng-init='sync($last)'/>
</td>
</tr>
</tbody>
</table>
</div>
</body>
Your controller should look like below
var app=angular.module('app',[])
app.controller('ctrl',function($scope){
$scope.myData=['a','b','c']
$scope.sync=function(val)
{
alert(val)
$scope.counter=val
}
})
Since you have stored (array|filter:{...}) value into filteredArray, you cannot modify it in the template.
You should repeat (array|filter:{...}) code in the template.
<h1 ng-if="!(array|filter:{...}).length">Empty array</h1>
<table ng-if="(array|filter:{...}).length">
<tr ng-repeat="element in (array|filter:{...})">
<td>{{element}}</td>
</tr>
</table>

ng-repeat with click modifying input

<input ng-model = "val">
<a href ng-click="val = 1"> val = 1 </a>
<div class="test" ng-controller="Ctrl">
<table>
<thead>
<tr>
<th>let</th>
<th>num</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="thing in data">
<td>
<a href ng-click="val = 1">
{{thing.let}}
</a>
</td>
<td>{{thing.num}}</td>
</tr>
</tbody>
Is there a way to make an input change based on a click in an ng-repeat?
In this jsfiddle you can the input change with a click outside of an ng-repeat, but in the repeat it doesn't change the input.
http://jsfiddle.net/Hp4W7/2403/
The problem is that you are setting the val property in a child scope created by ng-repeat.
The solution is to create a function that assigns this value to the parent scope:
$scope.changeVal = function(val){
$scope.$parent.val = val;
}
And call it with ng-click="changeVal(1)"
Fiddle here: http://jsfiddle.net/nawd7jjc/
ng-repeat always make new scope for every iteration so if you change any primitive value inside ng-repeat ("val" in this case) then it will not refer to the actual "val". So to solve it, it should be a object type, for ex. obj.val something
Below is the working solution for this problem:
<div class="test" ng-controller="Ctrl" ng-init="obj.val=12345">
<input ng-model = "obj.val">
<a href ng-click="obj.val = 2"> val = 2 </a>
<table>
<thead>
<tr>
<th>let</th>
<th>num</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="thing in data">
<td>
<a href ng-click="obj.val = thing.num">
{{thing.let}}
</a>
</td>
<td>{{thing.num}}</td>
</tr>
</tbody>
</table>
<div>

ng-show does not work with custom directive

I've just started using AngularJS and wanted to create a custom template directive for creating "in-place" editable tables. The idea would be to have something like:
<tr ng-repeat="customer in model.customers">
<ng-template ng-hide="customer === model.selectedCustomer"> <!-- display template-->
<td>{{customer.name}}</td>
</ng-template>
<ng-template ng-show="customer === model.selectedCustomer"> <!-- edit template -->
<td><input type="text" ng-model="customer.name"/></td>
</ng-template>
</tr>
It could then also be extended to specify a templateUrl e.g. <ng-template template-url="foo.html"></ng-template>
When I apply the ng-show directive to my custom directive it does not work. Here's the code for my directive:
var demo = angular.module("demo", [])
.directive("ng-template", function() {
return {
restrict: "E",
replace: true,
transclude: true
}
});
and HTML (http://jsfiddle.net/benfosterdev/ASXyy/):
<div ng-app="demo">
<table>
<tr ng-repeat="name in ['jane', 'john', 'frank']">
<ng-template ng-show="name !== 'frank'">
<td>{{name}}</td>
</ng-template>
</tr>
</table>
</div>
Furthermore, when I look at the generated HTML my custom directive doesn't even appear in the table:
<div ng-app="demo" class="ng-scope">
<ng-template ng-show="name !== 'frank'" class="">
</ng-template>
<table>
<tbody>
...
</tbody>
</table>
</div>
Essentially I'm trying to avoid writing code like this (setting the ng-show directive on every <td> element):
<table>
<tr ng-repeat="customer in customers">
<ng-template>
<td ng-hide="isSelected">{{customer.name}}</td>
<td ng-hide="isSelected">{{customer.age}}</td>
<td ng-hide="isSelected"><button ng-click="edit(customer)"</td>
<td ng-show="isSelected"><input type="text" ng-model="customer.name"/></td>
<td ng-show="isSelected"><input type="text" ng-model="customer.age"/></td>
<td ng-show="isSelected"><button ng-click="save(customer)"</td>
</ng-template>
</tr>
</table>
A couple of things occur to me when I look at your code.
ng-include offers very similar functionality to your proposal for extending ng-template. If you're going to load a view based on the state of the underlying model then I think this would be the way to go.
If you're not going to be loading the template from a separate view file, why not just use ng-show (or ng-if / ng-switch, which I prefer in most cases) on your td element?
Here is some example code using ng-include:
<table>
<thead>
<th>One</th>
<th>Two</th>
<th>Three</th>
<th></th>
</thead>
<tbody>
<tr ng-repeat="item in items" ng-include="getTemplate(item)"></tr>
</tbody>
</table>
Here is the full JSFiddle: http://jsfiddle.net/qQR6j/2.
Use ng-repeat-start and ng-repeat-end to specify the two alternative <tr> tags.
<div ng-app="demo">
<table ng-controller="Ctrl">
<tr ng-repeat-start="name in ['jane', 'john', 'frank']" ng-hide="isSelected(name)">
<td>{{name}} <button ng-click="select(name)">edit</button></td>
</tr>
<tr ng-repeat-end ng-show="isSelected(name)">
<td>{{name}}!</td>
</tr>
</table>
</div>
With this javascript
var demo = angular.module("demo", []);
demo.controller("Ctrl",
function Ctrl($scope) {
var selected;
$scope.isSelected = function(name) {
return selected === name;
};
$scope.select = function(name) {
selected = name;
};
});
Live example: http://jsfiddle.net/6FtjG/1/
Your browser renders the 'ng-template' outside of the table because its not a valid child of tr. Even if you have set replace to true, the directive needs to be rendered before it can be replaced.
You can see it is because of the table, because this does work:
<div>
<div ng-repeat="name in ['jane', 'john', 'frank']">
<ng-template ng-show="name !== 'frank'">
<div >{{name}}</div>
</ng-template>
</div>
</div>
see: Fiddle
This is something your browser does so you cannot avoid it.

Resources