How to Display single object data with out Using ng-repeat? - angularjs

Aim :- To display only Single Object data.
Do I have to use ng-repeat to get the object ?
I'm relatively new to angular. Is there a better way to do this?
Html View :-
<div ng-controller="dashboardController">
<div ng-repeat="person in persons">
<span class="name">{{person.name}}</span>
<span class="title">{{person.title}}</span>
</div>
</div>
Controller Code :-
.controller('dashboardController', ['$scope', function(scope){
scope.persons = [
{
name:"George Harrison",
title:"Goof Off extraordinaire"
}
];
}])
UPDATE FOR MY FELLOW NOOBS, array vs single data set:
scope.persons = [ <-- that creates an array. Cant believe I forgot that.
scope.persons = { <-- that creates a single data set

scope.persons is an array so you have to use ng-repeat.
if you your data is an object, you don't need to use ng-repeat.
ex:
your controller
.controller('dashboardController', ['$scope', function(scope){
scope.person ={
name:"George Harrison",
title:"Goof Off extraordinaire"
}
}]);
so your html:
<div ng-controller="dashboardController">
<div>
<span class="name">{{person.name}}</span>
<span class="title">{{person.title}}</span>
</div>

This can serve your cause with current Json Structure :
<div ng-controller="dashboardController">
<div>
<span class="name"> {{persons[0].name}} </span>
<span class="title"> {{persons[0].title}} </span>
</div>
</div>

Normally if you were only getting one item , it would be an object
$scope.beatle = {
name:"George Harrison",
title:"Goof Off extraordinaire"
}
then reference that directly in view
{{beatle.name}}

Related

how to bind $index from ng-repeat to controller

In Angular I wanted to bind $index to controller. How can I send $index value in to my controller. Here is my html code.
<body>
<div class="container">
<div class="row row-content" ng-controller="demoController as demoCtrl">
<ul>
<li ng-repeat="val in demoCtrl.list" >Hello {{$index}}</li>
</ul>
</div>
</div>
Here is my controller code
var app = angular.module('confusionApp',[])
app.controller('demoController', function(){
var list = [1,2,3,4,5];
this.list = list;
var array = ['abc','def','ghi','jkl','mno']
this.array = array
console.log(this.array[index]);
});
I need to use ng-modal in HTML and bind that value to some variable in my controller.
Based on the selection of index, it should check in array and respective array should have to print.
Can any of you please help
To get your current iteration position in your controller you have define a function.
So your html code like this.
<body>
<div class="container">
<div class="row row-content" ng-controller="demoController as demoCtrl">
<ul>
<li ng-repeat="val in demoCtrl.list" ng-click="dispArray($index)">Hello {{$index}}</li>
</ul>
</div>
</div>
And your controller code
var app = angular.module('confusionApp',[])
app.controller('demoController', function($scope){
$scope.dispArray = function(index){
// console.log(index);
// your code
}
});
Depending on what you're trying to accomplish you might be better served creating a custom iterator.
function makeIterator(array){
var nextIndex = 0;
return {
next: function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
Angular is going to iterate over everything in the list when you use ngRepeat. If you're trying to track which list item a user clicks then you'll just add that in there using $index.
<li ng-repeat="val in demoCtrl.list" >
<span ng-click="demoCtrl.userClicked($index)"> Hello {{$index}}</span>
</li>
If you're just trying to print the data in each item, ng-repeat is already iterating everything for you.
<li ng-repeat="val in demoCtrl.list" >
<span ng-click="demoCtrl.userClicked($index)"> Hello {{val}}</span>
</li>
It all depends on what you're trying to do.
i dont konw what u want to do. if u want to use event. you can pass $index to your controller function like:
<li ng-repeat="val in demoCtrl.list" ng-click="getIndex($index)">Hello {{$index}}
$scope.getIndex = function($index) {
console.log($index)
}
hope to help u.

Test if an object is an empty object in a AngularJS template

I have a simple object in a controller which can sometimes be empty ({}).
app.controller('TestController', function() {
var vm = this;
vm.testObject = {};
});
I want to hide or show some DOM-elements in the corresponding template when the object is empty or not.
I tried to do it with a simple <div ng-if="vm.testObject"> but when vm.testObject === {} it is considered true in the ng-if.
<div ng-controller="TestController as vm">
<div ng-if="vm.testObject">
Test Object is not empty
</div>
<div ng-if="!vm.testObject">
Test Object is empty
</div>
</div>
Is there a simple way to check for an empty object in the template? Preferably without adding new variables to the scope.
Here is a working Plunker:
http://plnkr.co/edit/Qed2MKmuedcktGGqUNi0?p=preview
You should use an AngularJs filter:
Javascript:
app.filter('isEmpty', [function() {
return function(object) {
return angular.equals({}, object);
}
}])
Html template:
<div ng-if="!(vm.testObject | isEmpty)">
Test Object is not empty
</div>
<div ng-if="vm.testObject | isEmpty">
Test Object is empty
</div>
Updated plunkr: http://plnkr.co/edit/J6H8VzUKnsNv1vSsRLfB?p=preview
Are you ok with moving the equality check to the ng-if?
<div ng-controller="TestController as vm">
<div ng-if="!equals({}, vm.testObject)">
Test Object is not empty
</div>
<div ng-if="equals({}, vm.testObject)">
Test Object is empty
</div>
</div>
Otherwise, provide a helper on the scope
app.controller('TestController', function() {
var vm = this;
vm.testObject = {};
vm.empty = function() {
return vm.testObject === {};
};
});
then
<div ng-controller="TestController as vm">
<div ng-if="!vm.empty()">
Test Object is not empty
</div>
<div ng-if="vm.empty()">
Test Object is empty
</div>
</div>
This is an old thread but I find easier to check if the Object has keys.
<div ng-controller="TestController as vm">
<div ng-if="Object.keys(vm.testObject).length">
Test Object is not empty
</div>
<div ng-if="!Object.keys(vm.testObject).length">
Test Object is empty
</div>
</div>
It's simple and readable.
This will work. check the Length
<div ng-if="!!vm.testObject && vm.testObject.length > 0">
Test Object is not empty
</div>
You can convert the object to a JSON string using the built-in AngularJS json filter and do a comparison like this:
<div ng-if="vm.testObject | json) != '{}'">
Test Object is not empty
</div>

AngularJS: Access models using dynamic names in template

I have a template with a lot of what is essentially duplicate code. I'd like to use a directive to include a partial template which I can manipulate for each "block" of duplicate code.
The template currently looks something like this:
<div class="column book">
<div class="header">
<input type="text" id="book_query" ng-model="book_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="book in books | filter:book_query">
{{book.name}}
</div>
</div>
</div>
....
<div class="column game">
<div class="header">
<input type="text" id="game_query" ng-model="game_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="game in games | filter:game_query">
{{game.name}}
</div>
</div>
</div>
....
And the controller just gets the data and adds it to the scope e.g.
$scope.books = data.books;
$scope.games = data.games;
What I started doing was using a directive which takes in an argument (e.g. book, game etc) so I then knew which model(s) to use. The problem I have is how to use the argument to access the model in the template? The directive itself is, currently, very simple:
<div item-column item="book"></div>
<div item-column item="game"></div>
app.directive('itemColumn', function() {
return {
scope: {
item: '#'
},
replace: true,
templateUrl: 'item_column.html'
};
});
In item_column.html, I was hoping I could just substitute the item argument, which works fine for displaying the value of the arg but not for replacing where 'book' or 'game' is used for the models e.g.
<div class="column {{item}}">
<div class="header">
<input type="text" id="{{item}}_query" ng-model="{{item}}_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in ??? | filter:{{item}}_query">
{{item.name}}
</div>
</div>
</div>
Can someone show me the best way of doing this? I don't doubt I'm going the complete wrong way about it!
EDIT: The original issue above is now pretty much fully solved using JoseM's answer below. The one outstanding issue is the on-click functions on each element no longer firing the parent scope from within the isolated scope.
My controller is laid out like so:
app.controller('ItemsCtrl', ['$scope', '$http', 'CONFIG', function($scope, $http, CONFIG) {
var items = ['books', 'games'];
items.forEach(function(item) {
$scope[item] = [];
$scope['selected_'+item] = null;
})
$scope.getItem = function(item) {
$http.get('?action=get_item&id='+item.id+'&type='+item.type)
.success(function(data) {
// update model
})
.error(function(data, status) {
// do something
});
}
}]);
$scope.getItem is no longer accessible when clicking on the item in the view, which looks similar to the following after implementing JoseM's answer:
<div class="row" ng-repeat="item in array | filter:query">
<div class="text" ng-click="getItem(item)">
{{item.name}}
</div>
</div>
Is there a simple way of making the parent scope functions available from within the isolated scope? Or is there a better place for these functions? Apologies for (what I feel are) the very basic questions - I'm still trying to get my head around Angular!
One way to accomplish what you want is by using a child scope in your directive and then doing your own "linking" of the parent scope variables using a watch on the parent scope value.
in your directive:
app.directive('itemColumn', function() {
return {
scope: true,
templateUrl: 'item_column.html',
link: function(scope,elem,attrs) {
var varName = scope.varName = attrs.item;
var parScope = scope.$parent;
parScope.$watch(varName + 's', function(newVal){
scope.theArray = newVal;
});
parScope.$watch(varName + '_query', function(newVal){
scope.theQuery = newVal;
});
}
};
});
in your template:
<div class="column {{varName}}">
<div class="header">
<input type="text" ng-attr-id="{{varName}}_query" ng-model="theQuery.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in theArray | filter:theQuery">
{{item.name}}
</div>
</div>
</div>
If you want to use an isolated scope, you could it, but then you would have to supply at least 3 attributes if you are using the same properties as above. I personally believe that using an isolated scope is a better way of doing it. See below how the isolated version is simpler:
isolated version of directive
app.directive('itemColumn2', function() {
return {
scope: {
label: '#',
array: '=',
query: '='
},
templateUrl: 'item_column2.html'
};
});
isolated version of template
<div class="column {{label}}">
<div class="header">
<input type="text" ng-attr-id="{{label}}_query" ng-model="query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in array | filter:query">
{{item.name}}
</div>
</div>
</div>
usage
<div item-column2 label="book" array="books" query="book_query"></div>
<div item-column2 label="game" array="games" query="game_query"></div>
And finally here is a sample plunker: http://plnkr.co/edit/OyEHR4ZhzYKvs4jeDfjD?p=preview

how to show exact content of ng-repeat using ng-click in angularjs

I am trying to show exact content when I click on data from ng-repeat.
<div ng-repeat="trailSpot in trail.wayPoints">
<a ng-click="viewState.showSpotDetails = !viewState.showSpotDetails">
<p>Spot {{$index + 1}}. {{trailSpot.wpName}}</p>
</a>
<p >{{trailSpot.wpDescription}}</p>
</div>
When I click the first wpName, I want to show wpDescription only about the first wpName on another div. What should I put in that div.
<div class="panel-body" ng-show="viewState.showSpotDetails">
<div>
???
</div>
</div>
Anybody has any tips on what I am trying to do?Thank you!
Just pass the object to assign the property like this:
http://jsfiddle.net/wLs8axLj/
JS
var app = angular.module('itemsApp',[]);
app.controller('ItemsCtrl',function($scope) {
$scope.items = [
{name:'Test 1',details:'Test 1 Details'},
{name:'Test 2',details:'Test 2 Details'}
];
$scope.showDetails = function(i) {
$scope.item_details = i.details;
};
});
HTML
<div ng-app="itemsApp" ng-controller="ItemsCtrl">
<ul>
<li ng-repeat="i in items" ng-click="showDetails(i)">{{i.name}}</li>
</ul>
<hr>
{{item_details}}
</div>

AngularJS (jsFiddle included): Scope variable not updated before sent to filter

Here's the jsFiddle: http://jsfiddle.net/VSph2/274/
I'm trying to make a filter with checkboxes.
When the user clicks the checkbox, it adds the id to an array called color_ids. I know that's working because I print the array in the console.
However, when I try to combine that with a filter, it doesn't work. I try to pass the $scope.color_ids array, but it is always passing an empty array and not passing the array with values in them.
app.controller('IndexCtrl', ['$scope', "Product", "Color", function($scope, Product, Color) {
...
// this method is triggered by a checkbox
$scope.toggleColorFilter = function(color_id) {
var index = $scope.color_ids.indexOf(color_id);
if (index > -1) {
$scope.color_ids.splice(index, 1);
} else {
$scope.color_ids.push(color_id);
}
console.log($scope.color_ids); //<-- prints the array properly with the new values.
};
}]);
and a filter that isn't working:
app.filter('productFilter', function(){
return function(input, color_ids) {
console.log(color_ids); //<-- prints an empty array all the time [ ]
return input;
}
})
This is my HTML
<h2>Products</h2>
<div class="filters col-two" ng-controller="IndexCtrl">
<h3>Color</h3>
<div ng-repeat="color in colors">
{{color.name}} <input type="checkbox" ng-model="color_ids" ng-change="toggleColorFilter(color.id)">
</div>
<h3>Shape</h3>
<h3>Material</h3>
</div>
<div class="products col-ten" ng-controller="IndexCtrl">
<div class="product" ng-repeat="product in products | productFilter:color_ids">
<h3>
{{ product.name }}
</h3>
<div class="product-thumbs">
<div class="image-wrapper" ng-repeat="product_color in product.products_colors">
<img src="{{ product_color.color.image.url }}" width="75" height="40">
</div>
</div>
</div>
</div>
I want the filter to eventually only show products with a color_id that exist in the color_ids array.
You have three divs with ng-controller="IndexCtrl" in your JSFiddle example. This is the problem. Each time the Angular compiler finds ng-controller in the HTML, a new scope is created.
<div class="filters col-two" ng-controller="IndexCtrl">
<h3>Color</h3>
<div ng-repeat="color in colors">{{color.name}}
<input type="checkbox" ng-model="color_ids" ng-change="toggleColorFilter(color.id)">
</div>
</div>
<div class="products col-ten" ng-controller="IndexCtrl">
<div class="product" ng-repeat="product in products | productFilter:color_ids">
{{ product.name }}
</div>
</div>
Simpliest way is to place this code in one controller and it will print 2 similiar arrays in your console:
<div ng-controller="IndexCtrl">
<div class="filters col-two">
<h3>Color</h3>
<div ng-repeat="color in colors">{{color.name}}
<input type="checkbox" ng-model="color_ids" ng-change="toggleColorFilter(color.id)">
</div>
</div>
<div class="products col-ten">
<div class="product" ng-repeat="product in products | productFilter:color_ids">
{{ product.name }}
</div>
</div>
</div>
JSFiddle
The filter is applied before the color_ids is updated, you should apply the filter in the controller inside the toggle function:
$filter('productFilter')($scope.products, $scope.color_ids);
Here is the working findle (at least I think): http://jsfiddle.net/VSph2/276/
Don't forget to inject the $filter in your controller.

Resources