Check for empty ng-repeat from controller - angularjs

I'm a newbie in angularjs. And my template is something like this:
<div ng-repeat="item in values"></div>
<div ng-repeat="item1 in values1"></div>
And my controller:
$scope.openItems = function () {
$http.get('/api/openItems').success(function (data) {
$scope.values = data;
});
};
That is working fine. Now I want to show the items, only if it is empty.
I tried something like this:
$scope.openItems = function () {
$http.get('/api/openItems').success(function (data) {
if ($scope.values.length == 0) {
$scope.values = data;
} else {
$scope.values1 = data;
}
});
};
Any idea how to check from the controller is a ng-repeat has data in it?
Thanks in advance

Make sure you are initializing the arrays at the top, then you can just do something like this :
//initialize vars
$scope.values = [];
$scope.values1 = [];
$scope.openItems = function () {
$http.get('/api/openItems').success(function (data) {
if ($scope.values.length === 0) {
//you may or may not want to clear the second array if you are toggling back and forth
$scope.values1 = [];
$scope.values = data;
} else {
//empty the first one so we make the hide/show logic simple
$scope.values = [];
$scope.values1 = data;
}
});
};
then your html just looks like
<div ng-show="values.length" ng-repeat="item in values"></div>
<div ng-show="values1.length" ng-repeat="item1 in values1"></div>
Here is a quick proof of concept - http://jsfiddle.net/Lzgts/573/
You can also swap the ng-show with ng-if, if you want the divs to actually be taken off the DOM.

Depending on how your array is initialized (which we're not seeing) it might not ever have length==0 (for example I think it could be undefined, etc.) you could try:
if ($scope.values.length != 0) {
$scope.values1 = data;
} else {
$scope.values = data;
}

Related

Infinite Scrolling reloads page, Ionic

What is happening is that when I reach the bottom of the page, it refreshes and loads the new data, however it doesn't show the data for the previous and current page.
For example it looks like this:
1
2
3
4
* end of page, refreshes page*
5
6
7
8
My function in my controller:
var i = 0;
$scope.result = [];
$scope.noMoreItemsAvailable = false;
$scope.loadMore = function() {
if (i < 4) {
$http.get(url.recommended + i).success(function(response) {
i++;
$scope.result = $scope.result.push(response);
console.log(response);
$timeout(function() {
$scope.result = response
});
$scope.$broadcast('scroll.infiniteScrollComplete');
});
} else {
$scope.noMoreItemsAvailable = true;
}
}
HTML:
<div class="item item-text-wrap" ng-click="post($event,res)" ng-repeat="res in result" ng-controller="recommendedJobsCtrl" ui-sref="tabs.jobDetails">
<ul>
<li id="jobTitle">{{res.title }}</li>
</ul>
</div>
<ion-infinite-scroll ng-if="!noMoreItemsAvailable" on-infinite="loadMore()" distance="1%"></ion-infinite-scroll>
Well, there are 2 main problems:
You're attributing the value of the push for your array. You shouldn't do this, you just have to do this:
$scope.result.push(response);
You should remove this timeout because it's overriding what you already have:
$timeout(function() {
$scope.result = response
});
By the way, I'd recommend you to create a factory to prevent problems with async data.
You could do something like this:
angular
.module('app', [])
.controller("MainCtrl", MainCtrl)
.factory("ItemsFactory", ItemsFactory);
ItemsFactory.$inject = ['$http'];
function ItemsFactory($http) {
var factory = {
getPages: getPages
};
return factory;
function getPages(url) {
return $http.get(url);
}
}
Then, in your controller:
MainCtrl.$inject = ['$scope', 'ItemsFactory'];
function MainCtrl($scope, ItemsFactory) {
var url = 'https://www.google.com';
function getResponse(response) {
$scope.result.push(response.data);
}
function getError(response) {
console.log(response);
}
ItemsFactory.getPages(url)
.then(getResponse);
.catch(getError);
}
Please, note: I also recommend you to change the way that you're retrieving your items from your back-end. It isn't a good way to retrieve the elements 1 by 1. The correct in your case is to retrieve all the four items at once and treat them in controller.
Your timeout is causing the $scope.result to be overwritten by the response.
Just remove this and it should append the response to the result
REMOVE THIS
$timeout(function ()
{
$scope.result=response
});

md-select component loses ng-selected value

I work with Angular 1.5.4 & material 1.0.6. Everything of the following example is working fine if I use chrome. But if I use safari no value is preselected.
The template of the component looks like
<md-select ng-model="$ctrl.selectedFruit">
<md-option ng-repeat="fruit in $ctrl.fruits" ng-value="fruit" required
ng-selected="$first" >
{{fruit.name}} {{fruit.weight}}
</md-option>
</md-select>
the component looks like
.component('applicantAccount', {
// #ngInject
bindings: {
selectedFruit: "="
},
controller: function (accountService) {
var ctrl = this;
fruitService.initFruitBefore(function () {
ctrl.fruits= fruitService.getFruits();
});
},
templateUrl: 'views/templates/selectFruitTemplate.html'
});
fruitService:
var fruits = [];
var initFruits = function () {
return $http.get(configuration.apiUrl + "fruits")
.then(function success(response) {
fruits = response.data || []
return response;
})
};
var getFruits = function () {
var filterEx = {type: "fresh"};
return $filter('filter')(fruits , filterEx);
};
var initFruitBefore = function (callback) {
if (!areFruitsAvailable()) {
initFruits().then(callback);
}
else{
callback();
}
};
var areFruitsAvailable = function () {
return typeof fruits[0] !== 'undefined'
};
var getFreshFruit = function () {
var filterEx = {type: "fresh"};
var filtered = $filter('filter')(fruits, filterEx);
return filtered[0] || null;
};
controller:
fruitService.initFruitBefore(function () {
ctrl.selectedFruit = accountService.getFreshFruit();
ctrl.fruits = accountService.getFruits();
});
The odd thing(only safari) is, that ctrl.fruits gets initialized before selectedFruit is initialized (outside of the component). If this happens the value was shown for a short term.
Has anyone an idea whats going on? Why behaves the safari different?
Thank you & sorry for my bad english
The Solution
I added ng-model-options={trackBy:'$value.id'}.
Angular Material:
To determine whether something is selected, ngModelController is looking at whether $scope.selectedUser == (any user in $scope.users);;
Javascript's == operator does not check for deep equality (ie. that all properties on the object are the same), but instead whether the objects are the same object in memory. In this case, we have two instances of identical objects, but they exist in memory as unique entities. Because of this, the select will have no value populated for a selected user.
For futher description look at https://material.angularjs.org/latest/api/directive/mdSelect

How to find an array object according to given information?

I have an array in AngularJS controller like this:
$scope.persons = [{name:'Joey', age:'27'},{name:'Lucy', age:'22'}]
I have got a name 'Lucy', how can I get the age of the name in the controller (not in HTML)?
I've created a plunk here that outlines a single result, with just the age, as well as multiple results.
This could also be implemented within a filter, which is documented on the Angular site here: https://docs.angularjs.org/api/ng/filter/filter
https://plnkr.co/edit/OFRMzpQrZfTOnaFyJP7Z?p=info
angular.module('plnk',[]).controller('plnkCtrl', function($scope){
// Note, I added a second Joey here to test the multiple function.
// For output, check the browser console.
$scope.persons = [{name:'Joey', age:'27'},{name:'Joey', age:'28'},{name:'Lucy', age:'22'}]
console.log('Single -> ', getAgeSingle('Lucy'));
console.log('Multiple ->',getAgeMultiple('Joey'));
function getAgeMultiple(personLookup) {
var results = [];
angular.forEach($scope.persons,function(person){
if (person.name === personLookup) {
results.push(person);
// or results.push(person.age) for age only
}
});
return results;
}
function getAgeSingle(personLookup) {
var result = '';
angular.forEach($scope.persons,function(person){
if (person.name === personLookup && !result) {
result = person.age;
}
});
return result;
}
});
Just loop over the array and check, like this:
function getAge(name)
{
for (var i = 0; i < $scope.persons.length; i++)
{
var person = $scope.persons[i];
if (person.name === name)
{
return parseInt(person.age, 10);
}
}
return undefined;
}
This has a couple caveats -- if you have dupes you'll only get the first one and it runs in linear time. If you control the data source it'd be better to use a JS object/hashmap/dictionary/whatever you want to call it.
If you wanted to loop through the scope:
$scope.persons = [{name:'Joey', age:'27'}, {name:'Lucy', age:'22'}]
function getAge(name) {
angular.forEach($scope.persons, function (value, index) {
if (value.name === name) {
return parseInt(value.age, 10);
}
});
return undefined;
}
The HTML way:
<div ng-app="myApp" ng-controller="MainCtrl">
<table>
<tr ng-repeat="person in persons">
<td>Name: {{person.name}} Age: {{person.age}}</td>
</tr>
</table>
</div>
JS:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function ($scope) {
$scope.persons = [{name:'Joey', age:'27'}, {name:'Lucy', age:'22'}];
});

Filter Change the color of the word in the sentence angularjs

I want to change the color of the word in the sentence How can i do that?
Controller code:
app.controller("myController",function($scope){
$scope.phrase="This is a bad phrase";
});
app.filter('censor', function(){
return function(input){
var cWords = ['bad', 'evil', 'dark'];
var out = input;
for(var i=0; i<cWords.length;i++){
out = out.replace(cWords[i], <span class="blue"></span>);
}
return out;
};
})
My view:
{{phrase | censor}}
First of all, if you want to bind html in your filter, you need to use ngSanitize and binding with the directive: ng-bind-html instead of {{ }}, like this:
<p ng-bind-html="ctrl.phrase | censor"></p>
In your js file you need to check if the phrase contain any of the words you want to filter out, then update the phrase.
angular
.module('app', ['ngSanitize'])
.controller('MainCtrl', function() {
var ctrl = this;
ctrl.phrase = 'This is a bad phrase';
})
.filter('censor', function() {
return function(input) {
var cWords = ['bad', 'evil', 'dark'];
var splitPhrase = input.split(' ');
var out = splitPhrase.reduce(function(acc, curr) {
if (cWords.indexOf(curr) > -1) {
acc.push('<span class="blue">' + curr + '</span>');
} else {
acc.push(curr);
}
return acc;
}, []);
return out.join(' ');
}
});
You can find an example here: http://jsbin.com/koxekoq/edit?html,js,output

AngularJS ng-repeat: push object to array

I have an object for selectedProduct. I now want to create an array of these selectedProduct objects so I can build a list using ng-repeat. I;ve set the scope to an empty array but what is the angular way to push these so I can access them via ng-repeat, i.e. product in products.
$scope.products = [];
$scope.getProduct = function() {
ProductService.getProduct($scope.eanInput.ean)
.then(function(product) {
$scope.selectedProduct = product;
$scope.selectedProduct.ean = $scope.eanInput.ean;
$scope.selectedProduct.qtyInput = 1;
$scope.focusOn = 'qty';
$scope.eanInput.productFound = true;
})
.catch(function() {
$scope.eanInput.productFound = false;
});
};
To my knowledge there is no angular way of pushing an object into an array, you can just use the default javascript way:
$scope.products.push(product);
I would just push them to the array to be honest :
$scope.products = [];
$scope.getProduct = function() {
ProductService.getProduct($scope.eanInput.ean)
.then(function(product) {
$scope.selectedProduct = product;
$scope.selectedProduct.ean = $scope.eanInput.ean;
$scope.selectedProduct.qtyInput = 1;
$scope.focusOn = 'qty';
$scope.products.push(product)
$scope.eanInput.productFound = true;
})
.catch(function() {
$scope.eanInput.productFound = false;
});
};
then in html you can do :
<div ng-controller="YourCtrl">
<h1 ng-repeat="product in products">
{{product.ean}}
</h1>
</div>

Resources