Angular : ng-if with dictionaries - angularjs

Kind new to AngularJS I'm encountering the following problem :
How could eval with ng-if if a dictionary is empty or not ?
With arrays ng-if="myArray.length" works great but doesn't with dictionaries.
Edit : Also already tried Object.keys(myDict).length which doesn't work.

ng-if is also able to evaluate a function in scope.
For example:
<div ng-if="functionHere(x)" ></div>
Then in your controller, you could have
$scope.functionHere = function(input) { if [logic here]..... }
So, if you could contain your logic in a javascript function, then you could delegate the ng-if's decision to what the function returns.
JSFiiddle Example

Use a scope function:
html:
<div ng-app="myModule" ng-controller="myController">
<div ng-if="!isEmptyObject(myObj)">
<h1>Hello</h1>
</div>
</div>
javascript:
angular.module('myModule', [])
.controller('myController', ['$scope', function($scope) {
$scope.isEmptyObject = function(obj) {
for(var prop in obj) {
if(obj.hasOwnProperty(prop))
return false;
}
return true;
}
$scope.myObj = {};
}]);
Check out this fiddle

Related

ng-class using classes from variable under condition

I am using a directive and want to use ng-class in a way that I could output multiple classes (which are stored in a variable) under certain condition.
<div ng-if="showIcons" ng-class="{state.icon: showIcons}"></div>
$scope.state = {
icon: 'icon-cross-outline color-brand-danger'
};
Unfortunately this is not working.
Using ternary operator in ng-class, could you try the following?
<div ng-if="showIcons" ng-class="showIcons ? state.icon : null"></div>
Demo on Plunker
You can do more complicated stuff via binding a function to the ng-class see my plnker
JS:
var app = angular.module('hey', []);
app.controller('TheController', [function () {
this.title = "hey"
this.shouldApply = true;
this.canApplyClass = function () {
if (this.shouldApply == true) {
return 'happy sad other';
}
return '';
}
}]);
HTML:
<body ng-app="hey">
<div ng-controller="TheController as c">
<h1 ng-class="c.canApplyClass()">{{c.title}}</h1>
</div>
</body>
I prefer this approach because you can get complicated in the function - and even have access to other services.

Use this instead $scope on controller with provider

I´m learning about Providers. On a common controller I would use
modu.controller("thecontrol", [function()
{
this.something = "Hello";
]});
and on the HTML
<div ng-controller="thecontrol as ctrl">
{{ ctrl.something }}
</div>
But... I´m trying to the the same with this code and, I really could not, even when I tried all the ways I "know".
Here´s the code...
What I want? Use THIS instead of $scope
<div ng-app="myApp" ng-controller="showingName">
{{theNameIs}}
</div>
<script src="angular.js"></script>
<script>
var myApp = angular.module("myApp", []);
myApp.provider("showingName", function() {
this.name = "Luis";
this.$get = function() {
var name = this.name;
return {
showName: function() {
return name;
}
}
};
this.setName = function(name) {
this.name = name;
};
});
myApp.config(function(showingNameProvider){
showingNameProvider.setName("Juan");
});
myApp.controller("showingName", function($scope, showingName)
{
$scope.theNameIs = showingName.showName();
});
</script>
And yes... It works, but I would like to know if it´s possible to do it with THIS.
Thanks!
I think it's because when you don't name the controller, then the {{ }} has to be scope, since this and $scope can be different depending on the context. Say for instance in an ng-repeat, 1 controller yet essentially 2 scopes.
Name the controller like you did on the first, ctrl as showingName. Make the variable this.theNameIs and then use {{ ctrl.theNameIs }}
Also, personally I don't think you should name the controller and provider the same name, appreciate this is probably just an example.
More information on $scope and this:
'this' vs $scope in AngularJS controllers

AngularJS Passing scope to directive via a custom filter function $rootScope:infdig

I've created simple custom directive in angularJs. In that directive I am passing an array of objects as tableLayout. Please see my working jsfiddle with no errors.
JS Fiddle Working
However I need to pass a filtered tableLayout. I've created a function in the scope called filterFilterFn to filter the values and then pass it into the scope of my directive. When i do this I get a $rootScope:infdig error.
Js Fiddle w/ filterFunction NOT working
Reading another similar problem it was to do with the using the default filter in angularJs. Hence why I've have done a custom filter function in the scope. But I am still getting a same error. Advice on what I am doing wrong would be appreciated.
Non-working code below:
<div ng-app="myApp" ng-controller="mainCtrl">
<script type="text/ng-template" id="/template">
<button ng-click="testFn()">Test</button>
<div layout="row">
<div flex ng-repeat="col in [1,2,3]"><span>HEADER{{$index}}</span>
<div layout="column">
<div flex style="border: 1px solid black;" ng-repeat="row in [1,2,3]">{{$index}}</div>
</div>
</div>
</div>
</script>
<button ng-click="testFn()">Test 2</button>
<form-table table-layout=formFilterFn('table_id',1)></form-table>
</div>
var app = angular.module('myApp', ['ngMaterial']);
app.controller('mainCtrl', function($scope) {
$scope.tableLayout =[{"head_id":"GAP Assessment","table_id":"1","table_name":"GAP Table","element_id":"0","element_name":"Action Reference","sort_order":"0","is_multirow":"1","flex":"30","element_sort_order":"4","is_show":"0"},{"head_id":"GAP Assessment","table_id":"1","table_name":"GAP Table","element_id":"1","element_name":"Audit Criteria","sort_order":"0","is_multirow":"1","flex":"30","element_sort_order":"0","is_show":"1"},{"head_id":"GAP Assessment","table_id":"1","table_name":"GAP Table","element_id":"3","element_name":"Document Reference","sort_order":"0","is_multirow":"1","flex":"10","element_sort_order":"3","is_show":"1"},{"head_id":"GAP Assessment","table_id":"1","table_name":"GAP Table","element_id":"4","element_name":"Findings - General","sort_order":"0","is_multirow":"1","flex":"20","element_sort_order":"1","is_show":"1"},{"head_id":"GAP Assessment","table_id":"1","table_name":"GAP Table","element_id":"5","element_name":"Findings Details","sort_order":"0","is_multirow":"1","flex":"40","element_sort_order":"2","is_show":"1"}]
$scope.testFn=function(){
console.log("Test");
}
$scope.formFilterFn = function(key,value){
var output = [];
var input = $scope.tableLayout;
for (var x =0; x < Object.keys(input).length; x++){
if (input[x][key]==value){
output.push(input[x]);
}
}
return output;
}
});
app.directive('formTable', function() {
return {
scope:{tableLayout:'='},
link: function(scope,element,attrs){ // normal variables rather than actual $scope, that is the scope data is passed into scope
scope.column=[1,2,3];
scope.testFn=function(){
console.log(scope.tableLayout);
}
//function and scopes go here
},//return
transclude:true,
templateUrl: '/template',
restrict: 'E'
}
})
2 way bindings is causing the loop here, you can bind your scope with '&'.
Please check: http://jsfiddle.net/pa13f6gb/1/
scope:{ tableLayout:'&' },
From https://docs.angularjs.org/guide/directive:
"Because of this, '&' bindings are ideal for binding callback functions to directive behaviors."
I wouldn't personally call it a filter, just to avoid confusion with actual angular filters. Yes it's a filtering function.
The infinite digest is happening because the filter function is returning a new array every time. If you set a variable to the result of the filter, and bind the table to that, it should work.

Scope values to a requested content

I have a view that contains a button, when the button is clicked, a $http.get request is executed and the content is appended on the view.
View:
<button ng-click="includeContent()">Include</button>
<div id="container"></div>
Controller:
$scope.includeContent = function() {
$http.get('url').success(function(data) {
document.getElementById('container').innerHTML = data;
}
}
The content to include:
<h1>Hey, I would like to be {{ object }}</h1>
How can I scope a value to object? Do I need to approach this in a complete different way?
The built-in directive ng-bind-html is the way you are looking for.
Beware, that ng-bind-html requires a sanitized string, which is either done automatically when the correct libary is found or it can be done manually ($sce.trustAsHtml).
Don't forget to inject $sce in your controller.
$scope.includeContent = function() {
$http.get('url').success(function(data) {
$scope.data = $sce.trustAsHtml(data);
}
}
<button ng-click="includeContent()">Include</button>
<div ng-bind-html="data"></div>
As you also want to interpolate your requested HTML, I suggest using $interpolate or, if it can contain whole directives or should have a full fledged two-way-data-binding, use $compile instead.
In your case alter the assignment to
$scope.data = $sce.trustAsHtml($interpolate(data)($scope));
Don't forget to inject $interpolate/$compile aswell.
As I don't know about your $scope structure I assume that "object" is available in this scope. If this isn't the case then change the $scope parameter to whatever object contains your interpolation data.
You should use a controller to do this (I imagine you are since you're using $scope).
ctrl function () {
var ctrl = this;
ctrl.includeContent = function () {
$http.get("url").success(function (data) {
ctrl.object = data;
});
};
}
<div ng-controller="ctrl as ctrl">
<button ng-click="ctrl.includeContent()">Include</button>
<div id="container">
<h1 ng-show="ctrl.object">Hey, I would like to be {{ctrl.object}}</h1>
</div>
</div>
You need not select an element and append the data to it. Angular does it for you. That's what is magic about angular.
In your controller's scope, just update object and angular does the heavy-lifting
$scope.includeContent = function() {
$http.get('url').success(function(data) {
$scope.object = data;
}
}
If that's html code from a server, then you should use the 'ng-bind-html' attribute:
<button ng-click="includeContent()">Include</button>
<div id="container" ng-bind-html="htmlModel.ajaxData"></div>
Controller:
$scope.htmlModel = {ajaxData:''};
$scope.includeContent = function() {
$http.get('url').success(function(data) {
$scope.htmlModel.ajaxDataL = data;
}
}
One way is to use ng-bind-html as suggested.
Another way is with $compile:
app.controller('MainCtrl', function($scope, $http, $compile) {
$scope.error='error!!!';
$scope.includeContent = function() {
$http.get('url').success(function(data) {
var elm = angular.element(document.getElementById('container')).html(data);
$compile(elm)($scope);
}).error(function(){
var elm = angular.element(document.getElementById('container')).html('{{error}}');
$compile(elm)($scope);
})
}
});
Also, typically in angular, when you want to manipulate the DOM you use directives.
DEMO

AngularJS: ng-app inside ng-include

I have a template like this.
<body ng-app="demo" ng-controller="demo">
<div ng-include="/main.html">
</div>
</body>
And the main.html is.
<div ng-app="main" ng-controller="main>
""
</div>
here is the js.
JS-1
var myapp = angular.module('demo', []);
myapp.controller('demo', function($scope,$routeParams, $route,$http) {
$scope.variable="444"
})
JS-2
var mainapp = angular.module('mainapp', []);
myapp.controller('main', function($scope,$routeParams, $route,$http) {
})
Is it possible to access the scope of JS-1 inside JS-2?, if yes how, if no is there any solution to this.Thanks.
It depend what you want to do.
If you want read $scope.variable variable from JS-1, you should see it in JS-2 $scope.
If you want modify $scope.variable form JS-1, you should create method in JS-1:
$scope.changes = function(data){
$scope.variable = data;
}
This method also should be available in JS-2 $scope.
This isn't nice solution but should work.
The best solution is to create service which will provide operations on JS-1 fields.

Resources