ng-repeat with nested json objects - angularjs

I'm trying to create a nested ng-repeat that populates contacts names into buttons from the JSON objects. I cant seem to find the correct way to populate the info though. Can someone explain whats wrong with my ng-repeat?
http://plnkr.co/edit/B3g075?p=preview
<!-- Contacts List Section -->
<div class="col-md-3 contact-list">
<div class="list-group">
<a href="javascript:void(0);" ng-repeat="contact in groups.contacts" class="list-group-item" ng-click="selectContact(contact)">{{group.firstName}} {{group.lastName}}
<span ng-click="deleteContact()" class="onHover pull-right"><i class="fa fa-times"></i></span>
</a>
</div>
<button ng-click="isCreatingNewContact = true" class="btn btn-default"><i class="fa fa-plus"></i> New Contact</button>
</div>
$scope.groups has the following structure (shortened for brevity):
$scope.groups = [
{
name: "Personal",
contacts: [
{
"firstName": "Personal First Name",
"lastName": "last name",
// ...
},
{ /* another contact */ },
]
},
{
name: "Family",
contacts: [
// ...
]
},
];
Thanks

Notice how here:
<div class="col-md-3 group-list">
<!-- Groups Section -->
<h4>Contact Groups</h4>
<div class="list-group">
All Contacts
<a href="javascript:void(0);" ng-repeat="group in groups" class="list-group-item">{{group.name}}
<span ng-click="deleteGroup()" class="onHover pull-right"><i class="fa fa-times"></i></span>
</a>
</div>
<div class="col-bottom">
<button class="btn btn-default"><i class="fa fa-plus"></i> New Group</button>
</div>
</div>
You have an ng-repeat="group in groups" directive, iterating through the groups. The group you get while looping through groups is only active in the sub-scope of the <a> tag that you're calling the directive in.
You seem to want to get all of the contact objects of each object in groups. You'd have to iterate through the groups list again, and within that iteration, iterate through the objects in the group contacts. So something like:
<!-- Contacts List Section -->
<div class="col-md-3 contact-list">
<div class="list-group">
<div ng-repeat="group in groups">
<a href="javascript:void(0);" ng-repeat="contact in group.contacts" class="list-group-item" ng-click="selectContact(contact)">{{contact.firstName}} {{contact.lastName}}
<span ng-click="deleteContact()" class="onHover pull-right"><i class="fa fa-times"></i></span>
</a>
</div>
</div>
<button ng-click="isCreatingNewContact = true" class="btn btn-default"><i class="fa fa-plus"></i> New Contact</button>
</div>
Plunker: http://plnkr.co/edit/lqNd5yDC2QlrX0M9TjrP

Related

Controller runs multiple time on click of item in angularjs?

In web app i am showing list of items using ng-repeat directive of angularjs. And on-click of each item am assigning a summary controller to the summary page (using ui-routing) and shows the result. Currently what happens if there is 10 list items showed using ng-repeat then 10 times summary controller is getting initialized on click of one item. Eventually which makes my app bit slow. Here is my ng-repeat code in html.
<div class="surveyList" ng-repeat="survey in allSurveys | filter:headerObj.search track by $index">
<span class="surveycheckbox" ng-click="toggleClass($event)"></span>
<div class="toogleSurvey row" ng-mouseover="hoverIn()" ng-mouseleave="hoverOut()" ng-click="surveyIdForQuota(survey.SurveyID)">
<div class="col-xs-5 col-sm-2 col-md-4 surveyitleElipse">{{survey.SurveyName}}</div>
<div class="col-xs-5 col-sm-2 col-md-1">
<span class="title_thumb">
<span class='fa fa-mobile-phone' ng-show="survey.Type=='App'" title="APP" my-Tooltip />
<span class='fa fa-envelope-o' ng-show="survey.Type=='SMS'" title="SMS" my-Tooltip />
<span class='fa fa-desktop' ng-show="survey.Type=='Web'" title="WEB" my-Tooltip/>
</span>
</div>
<div class="col-sm-3 col-md-2 hidden-xs">{{survey.Date | date:'dd/mm/yyyy'}}</div>
<div class="col-sm-2 col-md-2 hidden-xs SurveyLastChild">124</div>
<div class="hidden-xs surveyListTool" ng-show="hoverEdit">
<a class="editSurvey" title="edit"><i class="fa fa-pencil fa-2"></i></a>
<a class="deleteSurvey" ng-click="sendsurveyID(survey.SurveyID)" data-surveyID="{{survey.SurveyID}}" ><i class="fa fa-trash-o fa-2"></i></a>
<a class="cloneSurvey" ng-click="cloneSurvey(survey.SurveyID)" title="clone"><i class="fa fa-clone fa-2"></i></a>
<a class="menuSurvey" title="menu">
<i class="fa fa-circle fa-2"></i>
<i class="fa fa-circle fa-2"></i>
<i class="fa fa-circle fa-2"></i>
</a>
</div>
</div>
<!-- On click Of the list am showing this div box -->
<div class="surveyDetailsBox"> <!--This is the header section -->
<div class="surveyDetailHead">
<p class="surveyTitle">{{survey.SurveyName}}</p>
<div class="surveyDetailHeadTool" >
<a class="editSurvey" title="edit" ng-click="showEditSurveyForm(survey.SurveyID,$index);"><i class="fa fa-pencil fa-2"></i></a>
<a class="deleteSurvey hidden-xs" ng-click="sendsurveyID(survey.SurveyID)" ><i class="fa fa-trash-o fa-2"></i></a>
<a class="menuSurvey" title="menu">
<i class="fa fa-circle fa-2"></i>
<i class="fa fa-circle fa-2"></i>
<i class="fa fa-circle fa-2"></i>
</a>
<a class="hidden-xs" title="close"><i class="fa fa-angle-up fa-2"></i></a>
</div>
</div>
<!--This is the body section where summary and other modules are present -->
<div class="surveyDetailContent hidden-xs" ng-if="is_desktop">
<div class="row">
<div class="col-xs-12 col-md-12">
<div class="col-xs-2 col-sm-2 col-md-2 leftMenu">
<div class="list-group">
<a ui-sref="survey.surveyList.details" class="list-group-item summary" ui-sref-active="active">Summary</a>
<a ui-sref="survey.surveyList.questionare" class="list-group-item " ui-sref-active="active">Questionaire Management</a>
<a ui-sref="survey.surveyList.sampleManagement" class="list-group-item " ui-sref-active="active">Sample Management</a>
<a ui-sref="survey.surveyList.quotaManagement" class="list-group-item " ui-sref-active="active">Quota Management</a>
<a ui-sref="survey.surveyList.scheduling" class="list-group-item " ui-sref-active="active">Scheduling</a>
<a ui-sref="survey.surveyList.notification" class="list-group-item " ui-sref-active="active">Notifications</a>
<a ui-sref="survey.surveyList.reports" class="list-group-item " ui-sref-active="active">Reports</a>
<a ui-sref="survey.surveyList.location" class="list-group-item " ui-sref-active="active">Geolocation</a>
</div>
</div>
<div class="col-xs-10 col-sm-10 col-md-10 rightContent" ui-view></div>
</div>
</div>
</div>
For each sub module like Summary, questionnare etc., one controller is associated.
On click of this list am showing the summary box and running the controller also.
Code for surveyIdForQuota() goes here
$scope.surveyIdForQuota = function(SurveyID){
$rootScope.quotaSurveyID = SurveyID;
$scope.exportViewDetails="";
$http.get(__env.apiUrl+"/UserSurvey/GetInvitationCount?surveyId="+$rootScope.surveysummaryID,{headers:{"Content-type":"application/json",'sessionID':$rootScope.token}}).
then(function(response){
console.log(response);
$scope.summaryDetails = response.data;
},function(error){console.log(error)})
};
ng-click should be add on the item of list
<div class="surveyList" ng-repeat="survey in allSurveys |filter:headerObj.search track by survey.SurveyID"> <div ng-
click="surveyIdForQuota(survey.SurveyID)">)">//rest code inside goes here</div></div>
Your first div is a parent div, but you wrote ng-click on the list. So if you click any place of the div. it will be call the method

Dynamic div id for Multilevel accordion in Angular JS

I am new to AngularJS.
I have a 2- level accordion in my application.
<div class="box-group" id="accordion" ng-repeat="item in tourList">
<div class="panel box box-primary">
<div class="box-header with-border">
<h4 class="box-title">
<a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="false" class="collapsed">
{{item.Name}}
</a>
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse" aria-expanded="false" style="height: 0px;">
<div class="box-body">
<div class="box-group" id="accordion1" ng-repeat="itinerary in item.Itineraries">
<!-- we are adding the .panel class so bootstrap.js collapse plugin detects it -->
<div class="panel box box-primary">
<div class="box-header with-border">
<h4 class="box-title">
<a data-toggle="collapse" data-parent="#accordion1" href="#collapseItin" aria-expanded="false" class="collapsed">
{{itinerary.Name}}
</a>
</h4>
</div>
I want to create dynamic id for the accordion div and also assign it to the parent accordion.
Any help!
You can create the dynamic id by making use of the implicit $index property exposed by the ngRepeat directive. In order to deal with nested ngRepeat's you can also alias the $index property via the ngInit directive. This makes it clear which $index property is being referenced where.
Given ...
angular.module('app', [])
.controller('ctrl',
function($scope) {
$scope.tourList = [{
Name: "Tour 1",
Itineraries: [{
Name: "tour 1 itin 1",
Stops: ["A","B"]
}, {
Name: "tour 1 itin 2",
Stops: ["C","D"]
}]
}, {
Name: "Tour 2",
Itineraries: [{
Name: "tour 2 itin 1",
Stops: ["E","F"]
}, {
Name: "tour 2 itin 2",
Stops: ["G","H"]
}]
}]
}
);
... the following nested accordions work correctly ...
<div class="box-group" id="tourAccordion_{{tourIndex}}" ng-repeat="item in tourList" ng-init="tourIndex=$index">
<div class="panel box box-primary">
<div class="box-header with-border">
<h4 class="box-title">
<a data-toggle="collapse" data-parent="#tourAccordion_{{tourIndex}}" href="#collapse_{{tourIndex}}" aria-expanded="false" class="collapsed">{{item.Name}}</a>
</h4>
</div>
<div id="collapse_{{tourIndex}}" class="panel-collapse collapse" aria-expanded="false" style="height: 0px;">
<div class="box-body">
<div class="box-group" id="itineraryAccordion_{{tourIndex}}_{{itineraryIndex}}" ng-repeat="itinerary in item.Itineraries" ng-init="itineraryIndex=$index">
<!-- we are adding the .panel class so bootstrap.js collapse plugin detects it -->
<div class="panel box box-primary">
<div class="box-header with-border">
<h4 class="box-title">
<a data-toggle="collapse" data-parent="#itineraryAccordion_{{tourIndex}}_{{itineraryIndex}}" href="#collapseItin_{{tourIndex}}_{{itineraryIndex}}" aria-expanded="false" class="collapsed">{{itinerary.Name}}</a>
</h4>
</div>
<ul id="collapseItin_{{tourIndex}}_{{itineraryIndex}}" class="panel-collapse collapse">
<li ng-repeat="stop in itinerary.Stops">{{stop}}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
https://plnkr.co/edit/XQUq63
... for both ngRepeats I am using the available $index values (aliased for clarity/readability) to ensure that the IDs are unique.
NOTE: It is usual convention that property names should begin with a lower case letter. I have kept your naming convention simply for consistency between question and answer.

How to use spaces in json key and still be able to access in Angular?

i am currently having problem using key value from json and show it in accordian in angular. the key is working properly when there is no space in between and i am able to open the panel but when i add a space to make it look better i can't seem to open it.
Here is my code:
<div class="col-lg-8 col-sm-12">
<div class="panel-group" id="accordion">
<div ng-repeat="key in notSorted(items) track by $index" class="panel panel-default menu-panel" ng-init="value = items[key]" style="margin-bottom:10px;">
<a data-toggle="collapse" data-parent="#accordion" id="menu-link" href="#{{key}}">
<div class="panel-heading panel-types">
<h4 class="panel-title">
{{key}}
</h4>
</div></a>
<div id="{{key}}" class="panel-collapse collapsing menu-items">
<div ng-repeat="item in value">
<div class="row">
<div class="col-sm-12 col-lg-3">
<p class="item-name">
<span ng-if="item.itemtype=='veg'" class="fa-stack fa-lg text-success" title="Veg"> <i class="fa fa-square-o fa-stack-2x"></i> <i class="fa fa-circle fa-stack-1x"></i> </span>
<span ng-if="item.itemtype=='nonveg'" class="fa-stack fa-lg text-danger" title="Non Veg"> <i class="fa fa-square-o fa-stack-2x"></i> <i class="fa fa-circle fa-stack-1x"></i></span>
{{item.itemname}}
</p>
</div>
<div class="col-sm-12 col-lg-3">
<p><i class="fa fa-inr"></i> {{item.price}}</p>
</div>
<div class="col-sm-6 col-lg-6">
<a href ng-click="rprocess(item)"><span class="glyphicon glyphicon-minus"></span></a>
<span ng-bind-html="item.quantity|| 0"></span>
<a href ng-click="process(item)"><span class="glyphicon glyphicon-plus"></span></a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
and here is my sample json:
{
"Veg Starters": [
{
"itemname": "Paneer Tikka",
"itemtype": "veg",
"price": "110"
},
{
"itemname": "Mushroom Chilly",
"itemtype": "veg",
"price": "90"
},
{
"itemname": "Masala Papad",
"itemtype": "veg",
"price": "20"
}
]
}
Can anyone please look into it and help me figure out how to use it i have tried using {{key.replace(new RegExp(' ')}} in place of {{key}} to replace space but it doesn't seem to work.
Try surrounding the field name with UTF8 code
'\u0022Veg Starters\u0022'

Filter in ng-repeat on clicking Button

I have a Json which m getting in $scope.notifications.
**Json**
0:{
$$hashKey: "object:31"
action: "wrote a comment"
creationDate: "2015-11-23 13:48:55.0"
post: Object
seen: true
user: Object
}
This Json has a key : seen which can be either true or false . I have to filter out those objects in ng-repeat whose key :seen is= false on clicking button unread notifications.
and then again clear the filter on clicking All Notifications button.
HTML
<div class="col-xs-12 col-sm-6 col-md-8">
<ul class="notifications-action-menu text-center">
<li>
<button type="button" class="btn btn-link btnUnreadFilter active" data-filter="all" id="btnShowAll">All Notifications</button>
</li>
<li>
<button type="button" class="btn btn-link btnUnreadFilter" data-filter="unread" id="btnShowOnlyUnread" ng-click="actions.unreadNotifications()">Unread Notifications</button>
</li>
<ul></ul>
</ul>
</div>
<div class="col-xs-12">
<div id="notificationsListWrapper" ng-repeat="notification in notifications" ng-hide="{{notification.seen == seen}}">
<div class="notification-item" ng-class="{'read' : notification.seen == true}">
<div class=" no-click-bind mark-as-read-btn">
<button type="button" class="no-click-bind" data-toggle="tooltip" data-placement="top" data-original-title="Mark as read" ng-click="actions.redirectToPost(notification.post.uuid, $index)">
<i class="fa fa-check"></i>
</button>
</div>
<div class="notification-body">
<div class="notification-details">
<a href="" class="doc-profile-img"><img class="" alt="{{notification.user.authorName}}" ng-src="{{(notification.user.thumbnailUrl) ? notification.user.thumbnailUrl :'/assets/images/avatars/avatar_100x100.png'}}">
</a>
<a>{{notification.user.authorName}}</a><span class="notification-action"> {{notification.action}}</span>
<a href="/news/abcd" class="notification-url no-click-bind">{{notification.post.title}}
</a>
<div class="notification-meta"><i class="fa notification-type-icon fa-calendar"></i> <small class="notification-datetime text-muted" title="Thursday, January 21, 2016 at 5:26 pm">Jan 21 2016</small>
</div>
<div class="notification-actions"></div>
</div>
</div>
<div ng-if="notification.post.featuredAttachmentUrl != '' " class="notification-url-img"><img alt="" ng-src="{{notification.post.featuredAttachmentUrl}}"></div>
</div>
</div>
Try something like:
ng-repeat="notification in notifications | filter:seenFilter"
where seenFilter is set to {seen:true}, {seen:false} or true by the controller. Example:
$scope.actions.unreadNotifications = function(){
$scope.seenFilter = {seen:false}
}

Angular js filtering is needed at object property level instaed at object level for ng repeat

I am trying to search a list with input text entry,
<input disable-auto-close type="text" class="form-control" placeholder="Query" ng-model="query" stop-event />
</div>
</li>
<li role="presentation" ng-repeat="eachObj in objList | filter:query" >
<a class="dd-li-item" role="menuitem" tabindex="-1" >
{{eachObj.name}}
</a>
</li>
I realized that my filter is searching at object level, instead object name property level. I mean, if I type "a", it should search eachObj.name, instead eachObj. My current search is resulting if any property of eachObj contains "a" then it is showing that, instead only if eachObj.name contains "a" then only it should display that name. is there any simple fix for this.
The following are my sample json and dropdown :
<div class="dropdown">
<div class="smp-list-selected btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
<div class="smp-list-selected-label">{{sampleCtrl.dropdownSelectedLabel}}</div>
<div class="caret dropdown-caret"></div>
<div class="subscript-indicator" ng-if="sampleCtrl.isQualified(sampleCtrl.selectedsmp.id)">Qualified</div>
</div>
<ul class="dropdown-menu smp-list" role="menu" aria-labelledby="dropdownMenu1" auto-close="outsideClick">
<li role="presentation" >
<div class="input-group input-group-sm search-control-for-smps"> <span class="input-group-addon">
<span class="glyphicon glyphicon-search"></span>
</span>
<input disable-auto-close type="text" class="form-control" placeholder="Query" ng-model="query" stop-event />
</div>
</li>
<li role="presentation" ng-repeat="smpObj in sampleCtrl.smpList | filter:{name:query} " ng-click="sampleCtrl.selectsmp(smpObj)">
<a class="dd-li-item" role="menuitem" tabindex="-1" >
{{smpObj.name}}
<div class="subscript-indicator" ng-if="sampleCtrl.isQualified(smpObj.id)">Qualified</div>
</a>
</li>
</ul>
</div>
vm.smpList = [
{
"id": "3",
"name": "Check",
"status": "Sent"
},
{
"id": "4",
"name": "Tupper",
"status": "In"
},
{
"id": "8",
"name": "Dangi",
"status": "Out"
}
]
You can use the object notation of filter. So | filter:{<propName>:<Value>} to search properties of your items.
So in your case
<div ng-repeat="item in items | filter:{name:by}">
Will filter where the object.name contains the scope property by.
https://docs.angularjs.org/api/ng/filter/filter
See fiddle of it in action
http://jsfiddle.net/gfwex7jd/

Resources