ng-model value inside ng-repeat not working - javascript

Having difficulty to assign ng-model values inside ng-repeat
So i am repeating this div with an array of json objects. I can print the 'ID' value of the object inside any element. But i can't use that as the ng-model value for the checkbox inside. I must be doing something wrong here. Any idea what that is?
Will really appreciate it if someone can take a look.
Here is a codepen of the issue. Code pen link
.

value for the model that assign to the checkbox is boolean whether it is true or false, unless you define the value. but again it is only 2 options value.
so, rather than using id as model attribute, you might change it to some attribute that could store boolean value. why not using 'isSelected'
<div ng-controller="quoteController" ng-app="MyApp" class="benefits-container">
<!-- benefits -->
<div class="benefit" ng-class="{'selected': pe.id}" ng-repeat="pe in policyEnhancementsArr | filter: {type:'optional'}">
<div class="top">
<md-checkbox ng-model="pe.isSelected" class="blue"></md-checkbox>
<h5 class="item">{{pe.name}}</h5>
<h5 class="prize">{{pe.loading}}</h5>
</div>
<div class="bottom">
<p>{{pe.limitDisplay}}</p>
</div>
</div>
</div>
then update some isSelected value:
...
{
"id": "PVC022",
"name": "NCD Protector",
"limit": null,
"limitDisplay": "N/A",
"desc": "<TBC>",
"type": "optional",
"loading": 0.0,
"isSelected": true
},
...

i have done exactly the same code the difference is the filter that you applied on ng-bind. try reading the article i suggest use ng-value.
whats the difference between ng-model and ng-value

try using ng-repeat and ng-model withing the same line.
instead of this
<div class="benefit" ng-class="{'selected': pe.id}" ng-repeat="pe in policyEnhancementsArr | filter: {type:'optional'}">
<div class="top">
<md-checkbox ng-model="pe.id" class="blue"></md-checkbox>
use this
<div class="benefit" ng-class="{'selected': pe.id}" ng-repeat="pe in policyEnhancementsArr | filter: {type:'optional'}"
ng-model="pe.id">
<div class="top">
<md-checkbox class="blue"></md-checkbox>

Related

AngularJS: many times use ng-include

I have old project. In this moment i can not rewrite all to use ng-view and routes. So i have large html file and many unreadable code.
<div ng-if="f1">
<div>...</div>
</div>
<div ng-if="f2">
<div>...</div>
</div>
<div ng-if="f3">
<div>...</div>
</div> ....etc
I would like to break this code into blocks and use the ng-include to clean code. But then I will have a lot of this tag(> 10). Is it normal? Is there a way to reorganize the file differently?
<div ng-if="f1" ng-include="url1"> </div>
<div ng-if="f2" ng-include="url2"> </div>
<div ng-if="f3" ng-include="url2"> </div>
You should put your logic in an array in controller like this
$scope.paths = [
{url : "url1" , condition: $scope.f1},
{url : "url2" , condition: $scope.f2},
{url : "url3" , condition: $scope.f3},
];
And then use it in html like this
<div ng-repeat="item in paths"> <div ng-if="item.condition" ng-include="item.url"></div> </div>
You can create an array object and use ng-repeat on it.
HTML:
<div ng-repeat="template in templates">
<div ng-if="template.f" ng-include="template.url"> </div>
</div>
JS
//Array of objects that contain your checks and template urls
$scope.templates = [{
"url": value,
"f": value
}, {
"url": value,
"f": value
}, .....,
{
"url": value,
"f": value
}];
It is good to use ng-route but if you are not comfortable then
here is one hack.
Create one json data like this:
$scope.myAllTemplate = [{
"isShown":false, "url":"/myTemplateURL1","templateName":"Template1"},{
"isShown":false, "url":"/myTemplateURL2","templateName":"Template2"},{
"isShown":false, "url":"/myTemplateURL3","templateName":"Template3"}
]
Rendering the name of template from where you have to toggle the ng-if by click event
<div ng-repeat="item in myAllTemplate ">
<anyTag ng-click="changeTemplate(item)">item.templateName</anyTag>
</div>
Controller function
$scope.changeTemplate = function(data){
data.isShown = true;
//here you can handle the template according to your wish
}
Finally, render the template
<div ng-repeat="item in myAllTemplate ">
<div ng-if="item.isShown" ng-include="item.url"></div>
</div>

ng-repeat through object with value as an array angular

I have an object with key value pairs that looks like this. You will see that the key has an array as its value.
$scope.testObj = {
"London":[
{"id":1,"city":"London","country":"GB","name":"Test1"},
{"id":4,"city":"London","country":"GB","name":"Test2"}
],
"Los Angeles":[
{"id":8,"city":"LA","country":"US","name":"Test3"}
]
}
I want to display the name next to the city in the front end using angular. To do this I have tried many approaches, and used track by $index, but cannot figure out how to get this working.
<div ng-repeat="(key, val) in jobsByCity track by $index">
{{key}}:{{val[$index].name}}
</div>
I have looked at this approach too, nesting ng-repeat
<div ng-repeat="(key, val) in testCity">
{{key}}
<div ng-repeat="test in val[$index].name">
{{test}}
</div>
</div>
Just use another ng-repeat to iterate over the value:
<div ng-repeat="(key, val) in jobsByCity">
<div ng-repeat="subValue in val track by $index">
{{key}}:{{subValue.name}}
</div>
</div>
Also note that your Los Angeles property needs to be in quotes, otherwise it isn't valid javascript.
See this jsfiddle

Editing property from Object in ng-repeat from LocalStorage

I'm listing an array of objects saved into Localstorage in a table-like layout.
Each row displays data saved in a particular object. I want to be able to edit and update certain properties from the object once it has already been saved into LocalStorage.
This is how a couple of my objects looks like:
[{
"date":"2014 10 16",
"time":"20.22",
"car":"396",
"driver":"Seb",
"from":"A",
"destination":"B",
"pax":"3",
"arrival":"23.10"
},
{
"date":"2014 10 16",
"time":"23.22",
"car":"46",
"driver":"Eric",
"from":"C",
"destination":"E",
"pax":"3",
"arrival":"00.10"
}]
So far my frontend code displaying the Destination property looks like this:
HTML
<div class="col-md-3"
ng-show="editItem == false"
ng-hide="editItem">{{record.destination}}</div>
// Shows current value
<div class="col-md-3"
ng-show="editItem == true"
ng-hide="!editItem">
<select class="form-control"
ng-model="locationList2"
ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
</div>
// Shows select with options to be picked to update property
<div class="col-md-1">
<button ng-click="editItem = !editItem"
ng-show="!editItem">Edit</button>
<button ng-click="editData(record); editItem = !editItem"
ng-show="editItem">Ok</button>
</div>
//Toggles between current value and select and triggers editData function
Relevant JS:
$scope.editData = function (record) {
record.destination = $scope.locationList2;
jsonToRecordLocalStorage($scope.recordlist);
}
So far when I trigger editData it just deletes the Destination property, it doesn't update it with the model of locationList2 from the Select.
What am I missing?
EDIT
Here's the complete ng-repeat piece of code:
<div class="row msf-row" ng-repeat="record in recordlist | filter: search">
<div class="col-md-1">{{record.time}}</div>
<div class="col-md-1"><strong>{{record.car}}</strong></div>
<div class="col-md-1">{{record.driver}}</div>
<div class="col-md-3">{{record.from}}</div>
<div class="col-md-3"
ng-show="editItem == false"
ng-hide="editItem">
{{record.destination}}
</div>
<div class="col-md-3"
ng-show="editItem == true"
ng-hide="!editItem">
<select class="form-control"
ng-model="locationList2"
ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
</div>
<div class="col-md-1">{{record.pax}}</div>
<div class="col-md-1">
<button
ng-click="editItem = !editItem"
ng-show="!editItem">
<i class="fa fa-pencil"></i>
</button>
<button
ng-click="editData(record); editItem = !editItem"
ng-show="editItem">
<i class="fa fa-check"></i>
</button>
</div>
</div>
Also, I here's a Plunkr to ilustrate the issue!
Add a driver, car code and location before starting to see the app running and the mentioned problem.
You could use angular-local-storage as an abstraction over LocalStorage API.
If you want to just hack it, you can do something along localStorage.setItem('data', JSON.stringify(data)) when setting data and use JSON.parse(localStorage.getItem('data')) to extract it. LocalStorage doesn't deal with objects by default so we have to serialize it.
Regardless of the solution you choose, it could be a good idea to extend your edit a bit:
$scope.editData = function (recordlist) {
$scope.recordlist.destination = $scope.locationList2;
// replace whole LocalStorage data here now. no need to "patch" it
updateLocalStorage('data', <data containing your objects goes here>);
}
If you have multiple ways to modify the data and want to avoid explicit update, you could set up a watcher instead:
$scope.$watch(<data name goes here>, function(newVal) {
// update your LocalStorage now
});
Why it fails with ng-repeat?
The reason you see the behavior is quite simple. $scope.locationList2 is a single variable that gets bound for each member created by ng-repeat. That explains why it stays empty during edit.
You will need to bind the data using some other way. Consider binding it directly to your record models. Example: AngularJS - Using $index in ng-options .
Solution
The original code had bits like this:
JS:
$scope.editData = function (record) {
record.destination = $scope.location;
jsonToRecordLocalStorage($scope.recordlist);
};
HTML:
<select class="form-control" ng-model="location" ng-options="location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
Note that the markup is inside a ng-repeat and effectively each item created by it points at the same location! This isn't good.
To make it work I changed it like this:
JS:
$scope.editData = function () {
jsonToRecordLocalStorage($scope.recordlist);
};
HTML:
<select class="form-control" ng-model="record.destination" ng-options="location.place as location.place for location in locationlist | orderBy:'place'">
<option value="">Destination</option>
</select>
As mentioned above the JS could be replaced by a watcher. The important thing to note here is that I bind the data directly to the records. That avoid hassle at editData and more importantly gets rid of the problematic ng-model reference.

Pass parameter to Angular ng-include

I am trying to display a binary tree of elements, which I go through recursively with ng-include.
What is the difference between ng-init="item = item.left" and ng-repeat="item in item.left" ?
In this example it behaves exactly the same, but I use similiar code in a project and there it behaves differently. I suppose it's because of Angular scopes.
Maybe I shouldn't use ng-if, please explain me how to do it better.
The pane.html is:
<div ng-if="!isArray(item.left)">
<div ng-repeat="item in [item.left]" ng-include="'Views/pane.html'">
</div>
</div>
<div ng-if="isArray(item.left)">
{{item.left[0]}}
</div>
<div ng-if="!isArray(item.right)">
<div ng-repeat="item in [item.right]" ng-include="'Views/pane.html'">
</div>
</div>
<div ng-if="isArray(item.right)">
{{item.right[0]}}
</div>
<div ng-if="!isArray(item.left)">
<div ng-init = "item = item.left" ng-include="'Views/pane.html'">
</div>
</div>
<div ng-if="isArray(item.left)">
{{item.left[0]}}
</div>
<div ng-if="!isArray(item.right)">
<div ng-init="item = item.right" ng-include="'Views/pane.html'">
</div>
</div>
<div ng-if="isArray(item.right)">
{{item.right[0]}}
</div>
The controller is:
var app = angular.module('mycontrollers', []);
app.controller('MainCtrl', function ($scope) {
$scope.tree = {
left: {
left: ["leftleft"],
right: {
left: ["leftrightleft"],
right: ["leftrightright"]
}
},
right: {
left: ["rightleft"],
right: ["rightright"]
}
};
$scope.isArray = function (item) {
return Array.isArray(item);
}
});
EDIT:
First I run into the problem that the directive ng-repeat has a greater priority than ng-if. I tried to combine them, which failed. IMO it's strange that ng-repeat dominates ng-if.
It's a little hacky, but I am passing variables to an ng-include with an ng-repeat of an array containing a JSON object :
<div ng-repeat="pass in [{'text':'hello'}]" ng-include="'includepage.html'"></div>
In your include page you can access your variable like this:
<p>{{pass.text}}</p>
Pass parameter to Angular ng-include
You don't need that. all ng-include's sources have the same controller. So each view sees the same data.
What is the difference between ng-init="item = item.left" and ng-repeat="item in item.left"
[1]
ng-init="item = item.left" means - creating new instance named item that equals to item.left. In other words you achieve the same by writing in controller:
$scope.item = $scope.item.left
[2]
ng-repeat="item in item.left" means create list of scopes based on item.left array. You should know that each item in ng-repeat has its private scope
I am trying to display a binary tree of elements, which I go through recursively with ng-include.
I posted in the past answer how to display tree by using ng-include.
It might helpful: how-do-display-a-collapsible-tree
The main part here that you create Node with id wrapped by <scipt> tag and use ng-repeat:
<script type="text/ng-template" id="tree_item_renderer">
<ul class="some" ng-show="data.show">
<li ng-repeat="data in data.nodes" class="parent_li" ng-include="'tree_item_renderer'" tree-node></li>
</ul>
</script>
<ul>
<li ng-repeat="data in displayTree" ng-include="'tree_item_renderer'"></li>
Making a generic directive instead of ng-include is a cleaner solution:
Angular passing scope to ng-include
I am using ng-include with ng-repeat of an array containing string. If you want to send multple data so please see Junus Ergin answer.
See my code Snippet:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="">
<div ng-repeat="name in ['Sanjib Pradhan']" ng-include="'your_template.html'"></div>
<div ng-repeat="name in ['Chinmay Sahu']" ng-include="'your_template.html'"></div>
<script type="text/ng-template" id="your_template.html">
{{name}}
</script>
</div>

How can a data-bind to an element within a Kendo-Knockout listview?

I have a rather sophisticated template for Kendo ListView using knockout-kendo.js bindings. It displays beautifully. My problem is that I need to use the visible and click bindings in parts of the template, but I can't get them to work. Below is a simplified version of my template. Basically, deleteButtonVisible determines whether the close button can be seen, and removeComp removes the item from the array.
<div class='template'>
<div >
<div style='display:inline-block' data-bind='visible: deleteButtonVisible, event: {click: $parent.removeComp}'>
<img src='../../../Img/dialog_close.png'></img>
</div>
<div class='embolden'>#= type#</div><div class='label1'> #= marketArea# </div>
<div class='label2'> #= address# </div>
<!-- more of the same -->
</div>
The view model:
function CompViewModel() {
var self = this;
self.compData = ko.observableArray().subscribeTo("compData");
self.template = kendo.template(//template in here);
self.removeComp = function (comp) {
//do something here
}
}
html:
<div class="row" >
<div class="col-md-12 centerouter" id="compDiv" >
<div class="centerinner" id="compListView" data-bind="kendoListView: {data: compData, template: template}"></div>
</div>
</div>
finally, sample data:
{
type: "Comparable",
marketArea: "",
address: "2327 Bristol St",
deleteButtonVisible: true
},
Take in count that the deleteButtonVisible must be a property on the viewModel linked to the view.You are not doing that right now. The click element can v¡be access from the outer scope of the binding and remove the $parent.He take the method from the viewmodel. Take in count that every thing that you take on the vie must be present on the view model for a easy access.

Categories

Resources