I have two lists of stuff using ng-repeat. Then I want it to say "empty" if there are no items in a list.
Here's the updated version:
<!-- First List -->
<div ng-repeat="request in requests" ng-if="request.condition1 == 'something'">
{{request}}
</div>
<div>Empty list</div>
<!-- Second List (both use requests array but have different conditions-->
<div ng-repeat="request in requests" ng-if="request.condition22222 == 'something else'">
{{request}}
</div>
<div>Empty list</div>
Try this:
(function(angular) {
'use strict';
angular.module('app', [])
.filter('decorate', function() {
return function(input, model) {
return input.filter(function(val){
return val[model.prop] == model.val;
});
};
}).controller('MyController', ['$scope', '$filter', function($scope, $filter) {
$scope.requests = [{name:'Tom', age:23},{name:'Henry', age:23},{name:'Max', age:33}];
$scope.$filter = $filter;
}])
})(window.angular);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="MyController">
<div ng-init='items1=$filter("decorate")(requests, {prop:"age", val:23})'>First list(age=23):</div>
<div ng-repeat='item in items1' ng-if='items1.length > 0' >{{item | json}}</div>
<div ng-if='items1.length == 0'>Empty</div>
<br/>
<div ng-init='items2=$filter("decorate")(requests, {prop:"name", val:"Sam"})'>Second list(name=Sam):</div>
<div ng-repeat='item in items2' ng-if='items2'>{{item | json}}</div>
<div ng-if='items2.length == 0'>Empty</div>
</div>
</body>
You can check against the length of your list and show it conditionally:
<div ng-show="!requests.length">List is empty</div>
If you're working with an object you can use Object.keys although it may not be supported in some older browsers.
Related
I have three tabs that has different html inside ng-include. These tabs are shown using ng-repeat. Only one HTML template contains function call, but it's executed 3 times (once per ng-repeat iteration). What is wrong here and how to fix it?
var app = angular.module('myApp', [])
app.controller('myCtrl', [
'$scope',
function($scope){
$scope.randomFnc = function (i) {
console.log(i);
return "Placeholder text";
}
$scope.tabs = [
"a",
"b",
"c"
];
}
])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<div ng-repeat="tab in tabs">
<div ng-if="$index == 1">
{{$index}}<input type="text" value="" placeholder="{{randomFnc($index)}}"/>
</div>
<div ng-if="$index != 1">{{$index}}</div>
</div>
</div>
</div>
You can use ng-init though it is not highly recommended to achieve this. The reason why your function call is being executed thrice is because angular doesn't know if any $scope value has changed during each digest cycle. So the function will get executed for each digest cycles. In your case, it will get executed when the ng-if conditions become true as well as during the two digest cycles accounting a total of three. This is the reason why it gets executed 3 times with the value 1 regardless of the number of items in the array.
var app = angular.module('myApp', [])
app.controller('myCtrl', [
'$scope',
function($scope) {
$scope.x = {};
$scope.randomFnc = function() {
console.log("once");
$scope.placeholderText = "Placeholder text";
}
$scope.tabs = [
"a",
"b",
"c"
];
}
])
app.directive('trackDigests', function trackDigests($rootScope) {
function link($scope, $element, $attrs) {
var count = 0;
function countDigests() {
count++;
$element[0].innerHTML = '$digests: ' + count;
}
$rootScope.$watch(countDigests);
}
return {
restrict: 'EA',
link: link
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<div ng-repeat="tab in tabs">
<div ng-if="$index == 1" ng-init="randomFnc()">
{{$index}}<input type="text" value="" placeholder="{{placeholderText}}" />
</div>
<div ng-if="$index != 1">{{$index}}</div>
</div>
</div>
<track-digests></track-digests>
</div>
Call a method for 3 times because placeholder attribute or other attributes like this as class or ... can't define the ng- in angularjs, for solution we can use ng-init to handle it.
when you run the first you have repeat and then binding elements and then your angular attributes runs.
for best solution i refer to use model as object to binding placeholder on it, it's easily.
var app = angular.module('myApp', [])
app.controller('myCtrl', [
'$scope',
function($scope){
$scope.placeholder = "";
$scope.randomFnc = function (tab) {
$scope.placeholder = "Placeholder text";
}
$scope.tabs = [
"a",
"b",
"c"
];
//----2
$scope.randomFnc2 = function (tab) {
tab.placeholder = "Placeholder text";
}
$scope.tabs2 = [
{name: "a"},
{name: "b"},
{name: "c"},
];
}
])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<h1>better if you use model</h1>
<div ng-repeat="tab in tabs2">
<div ng-if="$index == 1" ng-init="randomFnc2(tab)">
{{$index}}
<input type="text" value="" placeholder="{{tab.placeholder}}"/>
</div>
<div ng-if="$index != 1">{{$index}}</div>
</div>
<h1>also you can</h1>
<div ng-repeat="tab in tabs">
<div ng-if="$index == 1" ng-init="randomFnc(tab)">
{{$index}}
<input type="text" value="" placeholder="{{placeholder}}"/>
</div>
<div ng-if="$index != 1">{{$index}}</div>
</div>
</div>
</div>
Below are my list of items :
$scope.items = [
{id=1,name:'code.lmn.1234.Lodashjs'},
{id=2,name:'xyz.Suv.Angularjs'},
{id=3,name:'www.kius.reactjs'}
]
Now I want to display last part of name so expected output is like below :
Lodashjs
Angularjs
reactjs
I don't want to create filter for this as that will impact performance. So is there any way to do this without filter?
var app = angular.module("myApp", []);
app.controller("myController", function ($scope) {
$scope.items = [
{id:1,name:'code.lmn.1234.Lodashjs'},
{id:2,name:'xyz.Suv.Angularjs'},
{id:3,name:'www.kius.react.js'}
]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<div ng-repeat="item in items">
<span >{{item.name}}</span>
</div>
</div>
Try this:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<div ng-repeat="item in items">
<span >{{ item.name.split('.').reverse()[0] }}</span>
</div>
</div>
Yes it's so simple.
Just copy paste the below code:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<div ng-repeat="item in items">
<span >{{(item.name).substr((item.name).lastIndexOf('.') + 1, (item.name).length)}}</span>
</div>
</div>
You can also use directive that will manipulate the name and return string after last "." dot.
<div ng-repeat="item in items" my-directive my-directive-fn="item.name">
app.directive("myDirective", function(){
return {
scope: {
"myDirectiveFn": "="
},
link: function(scope){
scope.myDirectiveFn.match(/([^.]+)$/);
}
}
});
Below is a snippet using AngularJS to get the JSON response.
On scrolling to the bottom of the page, I need to request repeatedly till the JSON array list is empty.
<section>
<div style="padding-top:60px" infinite-scroll="myPagingFunction()" infinite-scroll-distance="3" ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="news in newsList">
<div class="col-lg-3 col-md-4 col-sm-6" style="">
<div class="thumbnail">
<img src="{{news.coverUrl}}" class="img-responsive" alt="{{news.name}}"/>
<div class="caption">
<h4>{{news.name}}</h4>
</div>
</div>
</div>
<div class="visible-lg clearfix" ng-if="($index+1)%4 == 0"></div>
<div class="visible-md clearfix" ng-if="($index+1)%3 == 0"></div>
<div class="visible-sm clearfix" ng-if="($index+1)%2 == 0"></div>
</div>
</div>
</section>
<script src="js/jquery.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="js/ng-infinite-scroll.min.js"></script>
<script>
var offset = 0
var maxCount = 20
var app = angular.module('myApp', ['infinite-scroll']);
function myPagingFunction(){
app.controller('myCtrl', function($scope, $http) {
$http.get("news.json").then(function(response) {
$scope.newsList = response.data;
});
});
}
myPagingFunction();
</script>
<script src="js/bootstrap.min.js"></script>
Kindly help me in solving this.
Using jQuery + angular is not good
You must use angular way instead, and write some directives or listeners in run phase, but here's a better approach - use `ngInfiniteScroll plugin
You can simply use infinite Scroll services to easily achieve this ,
<ANY infinite-scroll='{expression}'
[infinite-scroll-distance='{number}']
[infinite-scroll-disabled='{boolean}']
[infinite-scroll-immediate-check='{boolean}']
[infinite-scroll-listen-for-event='{string}']>
Add ng-infinite scroll module in your application
for more info refer this [Documentation]:(https://sroze.github.io/ngInfiniteScroll)
You can use this simple directive and enjoy:
app.directive("scroll",['$window', function ($window) {
return function (scope, element, attrs) {
angular.element($window).bind("scroll", function () {
if (document.body.scrollHeight - $window.scrollY < 890) {
scope.$apply(function () {
scope.myPagingFunction();
});
}
});
};
}]);
and you can use this code for your situation
<section>
<div style="padding-top:60px" scroll ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="news in newsList">
<div class="col-lg-3 col-md-4 col-sm-6" style="">
<div class="thumbnail">
<img src="{{news.coverUrl}}" class="img-responsive" alt="{{news.name}}"/>
<div class="caption">
<h4>{{news.name}}</h4>
</div>
</div>
</div>
<div class="visible-lg clearfix" ng-if="($index+1)%4 == 0"></div>
<div class="visible-md clearfix" ng-if="($index+1)%3 == 0"></div>
<div class="visible-sm clearfix" ng-if="($index+1)%2 == 0"></div>
</div>
</div>
</section>
<script src="js/jquery.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="js/ng-infinite-scroll.min.js"></script>
<script>
var offset = 0
var maxCount = 20
var app = angular.module('myApp', ['infinite-scroll']);
app.controller('myCtrl', function ($scope, $http) {
$scope.myPagingFunction= function() {
$http.get("news.json").then(function (response) {
$scope.newsList = response.data;
});
}
});
app.directive("scroll",['$window', function ($window) {
return function (scope, element, attrs) {
angular.element($window).bind("scroll", function () {
if (document.body.scrollHeight - $window.scrollY < 890) {
scope.$apply(function () {
scope.myPagingFunction();
});
}
});
};
}]);
</script>
<script src="js/bootstrap.min.js"></script>
I am just trying to get the ng-show tag working and to test it, I have a hard coded example and even this doesn't work (it is visible when the page loads). Code below.
#{
ViewBag.Title = "Secure Environment Flex";
}
<div class="row">
<div class="col-md-12">
<h3>Secure Environment</h3>
</div>
</div>
<div ng-controller="SEFlexHomeController" ng-show="false">
<div >
<div >
<ul>
<li>Jobs</li>
<li>Models</li>
<li>Administration</li>
</ul>
<div id="tabs-Jobs" >
<h1>Welcome to this jobs tab</h1>
</div>
<div id="tabs-Models">
<h1>Welcome to this models tab</h1>
</div>
<div id="tabs-Administration" >
<h1>Welcome to this administration tab</h1>
</div>
</div>
</div>
</div>
This is driving me mad, why is it still visible? Could something else in CSS be overriding it and if so how can I tell?
EDIT: Ok I got it working with a basic variable in scope like suggested. Now I'm trying to link it up to the actual action. My code retrieves a list of permissions in the background and once those are retrieved, I want to either display the page or an error depending on if the user is permissioned. Whats bizarre now is that I have two sections, page and error, one with ng-show matching the determination function and one with the negated function. But they are both showing? If I change them both to be just the function "isPermissioned" then the top one shows and the bottom doesn't, so it looks like they are getting different values from the same function. Could this be because one is executing before the other and when the background method updates the permissions, it isn't triggering the data binding?
New HTML is
<div ng-controller="SEFlexHomeController" ng-show="isPermissioned">
<div class="row" id="TabsSet1">
<div class="col-md-12">
<ul>
<li ng-show="AuthService.canRunFlexJobs || AuthService.canRunHighPriorityFlexJobs">Jobs</li>
<li ng-show="AuthService.canViewFlexModels">Models</li>
<li ng-show="AuthService.canAdministerFlex">Administration</li>
</ul>
<div id="tabs-Jobs" ng-show="AuthService.canRunFlexJobs || AuthService.canRunHighPriorityFlexJobs">
<h1>Welcome to this jobs tab</h1>
</div>
<div id="tabs-Models" ng-show="AuthService.canViewFlexModels">
<h1>Welcome to this models tab</h1>
</div>
<div id="tabs-Administration" ng-show="AuthService.canAdministerFlex">
<h1>Welcome to this administration tab</h1>
</div>
</div>
</div>
</div>
<div ng-show="!isPermissioned">
<h3>You have no permissions to view Secure Environment pages</h3>
</div>
JavaScript
app.controller("SEFlexHomeController", ["$scope", "$http", "$modal", "$log", "$element", "$rootScope", "AlertsService", "AuthService", "SEApplicationService", function ($scope, $http, $modal, $log, $element, $rootScope, AlertsService, AuthService, SEApplicationService) {
$rootScope.closeAlert = AlertsService.closeAlert;
$scope.isDataLoading = false;
$scope.AuthService = AuthService;
$scope.show = false;
$scope.isPermissioned = function() {
return AuthService.canAdministerFlex || AuthService.canViewFlexModels || AuthService.canRunFlexJobs || AuthService.canRunHighPriorityFlexJobs;
}
}
]);
Auth service
function AuthService($log, $http) {
var authService = {
canRunFlexJobs: false,
canRunHighPriorityFlexJobs: false,
canViewFlexModels: false,
canApproveFlexModels: false,
canAdministerFlex: false
};
authService.getUserClaims = function () {
$http.post("/Admin/Auth/GetUserClaims")
.success(function (response, status, headers, config) {
if (response) {
angular.forEach(response.data, function (item) {
if (item.Value === "SEFlexJobRunner")
authService.canRunFlexJobs = true;
if (item.Value === "SEFlexHighPriorityJobRunner")
authService.canRunHighPriorityFlexJobs = true;
if (item.Value === "SEFlexModelViewer")
authService.canViewFlexModels = true;
if (item.Value === "SEFlexModelApprover")
authService.canApproveFlexModels = true;
if (item.Value === "SEFlexAdministrator")
authService.canAdministerFlex = true;
});
}
})
.error(function (reason, status, headers, config) {
console.log(reason);
});
}
authService.getUserClaims();
return authService;
};
Well for your given code:
<div ng-controller="SEFlexHomeController" ng-show="show">
<div >
<div >
<ul>
<li>Jobs</li>
<li>Models</li>
<li>Administration</li>
</ul>
<div id="tabs-Jobs" >
<h1>Welcome to this jobs tab</h1>
</div>
<div id="tabs-Models">
<h1>Welcome to this models tab</h1>
</div>
<div id="tabs-Administration" >
<h1>Welcome to this administration tab</h1>
</div>
</div>
</div>
</div>
JS:
myAngularApp.controller('SEFlexHomeController', ['scope', function($scope) {
$scope.show = false;
// do stuff here
}]);
https://docs.angularjs.org/api/ng/directive/ngShow
<!-- when $scope.myValue is truthy (element is visible) -->
<div ng-show="myValue"></div>
<!-- when $scope.myValue is falsy (element is hidden) -->
<div ng-show="myValue" class="ng-hide"></div>
I assume you mean it's visible as the page loads and then disappears? If that's the case, you're going to want to also use ng-cloak.
Keep in mind that the css used by ng-cloak isn't available until Angular loads, so most put CSS like this in the header of their document.
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak
{
display: none !important;
}
I have two directives defined in an angular.js module. The HTML element that is declared first executes its directive, but the second HTML element that uses the other directive does not execute it.
Given this HTML:
<div ng-app="myApp">
<div ng-controller="PlayersCtrl">
<div primary text="{{primaryText}}"/>
<div secondary text="{{secondaryText}}"/>
</div>
</div>
and this angular.js code:
var myApp = angular.module('myApp', []);
function PlayersCtrl($scope) {
$scope.primaryText = "Players";
$scope.secondaryText = "the best player list";
}
myApp.directive('primary', function(){
return {
scope: {
text: '#'
},
template: '<h1>{{text}}</h1>',
link: function(scope, element, attrs){
console.log('primary directive');
}
};
});
myApp.directive('secondary', function(){
return {
scope: {
text: '#'
},
template: '<h3>{{text}}</h3>',
link: function(scope, element, attrs){
console.log('secondary directive');
}
};
});
The resulting HTML is only the "primary" directive, and the "secondary" directive does not render:
<div ng-app="myApp" class="ng-scope">
<div ng-controller="PlayersCtrl" class="ng-scope">
<div primary="" text="Players" class="ng-isolate-scope ng-scope">
<h1 class="ng-binding">Players</h1>
</div>
</div>
</div>
The console output verifies this as well, as only the "primary directive" text is output.
Then if I switch the order of the primary and secondary elements, the secondary directive is executed and the primary directive is not:
<!-- reversed elements -->
<div secondary text="{{secondaryText}}"/>
<div primary text="{{primaryText}}"/>
<!-- renders this HTML (secondary, no primary) -->
<div ng-app="myApp" class="ng-scope">
<div ng-controller="PlayersCtrl" class="ng-scope">
<div secondary="" text="the best player list" class="ng-isolate-scope ng-scope">
<h3 class="ng-binding">the best player list</h3>
</div>
</div>
</div>
Why is this? What am I doing wrong?
div's are not void elements and require a closing tag.
<div ng-app="myApp">
<div ng-controller="PlayersCtrl">
<div primary text="{{primaryText}}"></div>
<div secondary text="{{secondaryText}}"></div>
</div>
</div>
Example