AngularJS : Nested controllers not working in ng-include - javascript

As per the AngularJS article (have a look in nested controller fragment), I'm trying to implement nested controllers with ng-include
index.html
<body id="spaWrapperApp" ng-app="spaWrapperApp">
<div class="container-fluid" id="wrapper" ng-controller="mainController">
<div class="navigation">
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f1.html')">
<span>Page 1</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f2.html')">
<span>Page 2</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f3.html')">
<span>Page 3</span>
</a>
</div>
<div id="content" >
<div ng-include="currentPage"></div>
</div>
</div>
<script type="text/javascript">
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
console.log($scope);
$scope.requestPage = function(friendlyURL){
console.log(friendlyURL);
$scope.currentPage = friendlyURL;
}
}]);
</script>
</body>
Page1 (code given below)file will injected in ng-include
<div>Testing page include 1</div>
<hr/>
<br/>
<div ng-controller="FirstController">
<p>1# {{ name }}</p>
<div ng-controller="SecondController">
<p>2# {{ name }}</p>
</div>
</div>
<script type="text/javascript">
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);
</script>
In the whole case the end result will be nested controller injected in ng-include area.
The issue is when I run that code that time this error is shown to me.
"Error: [ng:areq] Argument 'FirstController' is not a function, got undefined"
Any idea what exactly going wrong ?

Something unexpected going in AngularJS.
If you are using ng-include and try to inject pageX in that area and pageX contains some script, in that case pageX script not executed, for that I just write all the angularJS controllers handler in index.html only and it works fine for me.
like
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
$scope.requestPage = function(friendlyURL){
$scope.currentPage = friendlyURL;
}
}]);
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);

Related

Show HTML elements in JSON with Angular js

I am new in angular js, I am trying to format a json data with angular js.
Here is my json data
[
{"field_add_link": "Home"},
{"field_add_link": "About Us"}
]
here is my conroller
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController',function($scope, $http) {
$http.get('http://localhost/drupal3/menu')
.then(function(response) {
$scope.links = response;
});
});
and finally here is how i am fetching the json data with angular
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links" ng-bind-html="links">
<p>{{ link.field_add_link }}</p>
</div>
</div>
no output was shown after this, giving an error Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context. in the browser's console
but when I used ng-bind-html="links[0].field_add_link instead of ng-bind-html="links" and <p>{{ link[0].field_add_link }}</p> instead of <p>{{ link.field_add_link }}</p>
then i get Home as output 'without interpreting the tag'
Pls, how do I go about this?
First of all you dont need the ng-bind-html attribute on your div with ng-repeat. It should be on your p tag. Second, you need to bind link (the current element of the ng-repeat-loop) not links (the array). Although you need to look into the error [$sce:unsafe]. HTMl can only be bind to an element-body if it is trusted. For that you need to have, for example, a filter.
myApp.filter ('to_trusted', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml (text);
};
}]);
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link | to_trusted"></p>
</div>
</div>
You just need to move your ng-bind-html from div to <p> like following code.
<p ng-bind-html="link.field_add_link"></p>
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController', function($scope, $http) {
var data = [{"field_add_link": "Home"},
{"field_add_link": "About Us"}];
$scope.links = data;
//For demo, removed the http call
});
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-sanitize.js"></script>
</head>
<body ng-app="myApp">
<div class="col-md-8 content" ng-controller="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link"></p>
</div>
</div>
</body>

Can't append divs when using ng-switch-when AngularJS?

I am using ng-switch when method to append divs. This is the code created
<input type="checkbox" ng-model="data" />
<ng-switch on="data">
<span ng-switch-when="true">
<div class="firstSwitch"></div>
</span>
<span ng-switch-default>
<div class="secondSwitch"></div>
</span>
</ng-switch>
Its working fine now. But when i want to append something in the div.
Say, i want to append text using javascript inside secondSwitch div, but i can't append it because initially the secondSwitch div is not appended.
setTimeout(function(){
$(".secondSwitch").html("<p>Second Switch is displayed</p>");
$(".firstSwitch").html("<p>First Switch is displayed</p>");
},100);
Here the text is appended properly inside firstSwitch div because initially it is created but the text is not appended inside secondSwitch div because it's not created.
So, i can't append inside that div. So, how to overcome this problem guys. Here is the Plnkr
As you already noticed ng-switch modifies DOM and firstSwitch is not created initially. You should use binding to get this working. Here is working demo
<ng-switch on="data">
<span ng-switch-when="true">
<div class="firstSwitch"><p>{{firstText}}<p></div>
</span>
<span ng-switch-default>
<div class="secondSwitch"><p>{{secondText}}<p></div>
</span>
app.controller('MainCtrl', function($scope, $timeout) {
$scope.data = false;
$timeout(function(){
$scope.firstText = "First Switch is displayed";
$scope.secondText = "Second Switch is displayed";
},100);
Update
And here's demo for binding to html
Try this
<div class="secondSwitch"><div id="replacediv"></div></div>
var divElement = angular.element(document.querySelector('#replacediv'));
var appendHtml = $compile('<div>test</div>')($scope);
divElement.append(appendHtml);
you can use ng-show directive for this.
// Code goes here
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,$timeout) {
$scope.data = false;
$scope.show = false;
$scope.change = function(){
$timeout(function(){
$scope.show = !$scope.show;
},300);
}
});
<script src="http://code.jquery.com/jquery-1.12.2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="plunker">
<div ng-controller="MainCtrl">
<input type="checkbox" ng-model="data" ng-change="change()" />
Check
<ng-switch on="data">
<span ng-switch-when="true">
<div class="firstSwitch">
<p ng-show="show">First Switch is displayed</p>
</div>
</span>
<span ng-switch-default>
<div class="secondSwitch">
<p ng-show="!show">Second Switch is displayed</p>
</div>
</span>
</ng-switch>
</div>

Angularjs show hide css issue

I had a hard issue figuring out on how to hide and show icon/text with angular code. I am completely new to angular and tried hard on the below fiddle code. How do I hide + or minus icon with .closest in such dom scenarios.
<div ng-controller="MyCtrl">
{{name}}
<div data-toggle="collapse" aria-expanded="true" data-target="#list-item-line-0" id="expandCollapseChild" ng-click="addExpandCollapseChildIcon()">
<div>
<div>
<label>
<div>
<span class="icon-expand">-</span>
<span class="icon-collapse">+</span>
</div>
<div>
Click me to hide minus icon
</div>
</label>
</div>
</div>
</div>
</div>
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.addExpandCollapseChildIcon = function() {
alert('');
if (angular.element('#expandCollapseChild').hasClass('collapsed')) {
angular.element(this).closest('.icon-collapse').css('display', 'none');
} else {
if (angular.element('#expandCollapseChild').hasClass('collapsed')) {
angular.element(this).closest('.icon-collapse').css('display', 'block');
}
}
}
In Angular, this is the wrong approach. You shouldn't actually show or hide elements inside the controller. That's applying a jQuery style (working directly on the DOM) to Angular.
In Angular, you'd use something like ng-if, ng-show or ng-class, all of which can link back to a property on the scope object that is accessible via the controller.
Here are some examples:
<div ng-if="myProp === 'ShowMe'">
<div ng-show="myProp === 'ShowMe'">
<div ng-class="{myCssClass: myProp === 'ShowMe'">
Inside your controller, you'd have something like this:
function MyCtrl($scope) {
$scope.myProp = 'ShowMe';
$scope.addExpandCollapseChildIcon = function(newPropValue) {
$scope.myProp = newPropValue;
}
}
Here's some links to documentation on ng-if, ng-show and ng-class:
https://docs.angularjs.org/api/ng/directive/ngIf
https://docs.angularjs.org/api/ng/directive/ngShow
https://docs.angularjs.org/api/ng/directive/ngClass
AngularJS has a bunch of angulary ways of doing things, your question for example might look like this:
var app = angular.module("app", []);
app.controller("ctrl", function($scope) {
$scope.collapsed = true;
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl">
<span ng-bind="collapsed ? '+' : '-'"></span>
</div>
</div>
It watches a model and changes it's appearance based on that model using the ternary operator within ng-bind.
The way you defined your app and controller was incorrect. There's a bunch of different ways to do this as you can see from the answers.
I took this approach:
<div ng-app='myApp' ng-controller="MyCtrl">
{{name}}
<div>
<div>
<div>
<label>
<div>
<span ng-show='(collapsed != false)' class="icon-expand">-</span>
<span ng-show='(collapsed == false)' class="icon-collapse">+</span>
</div>
<div ng-click='collapsed = !collapsed'>
Click me to hide minus icon
</div>
</label>
</div>
</div>
</div>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope) {
$scope.name = 'Superhero';
$scope.collapsed = false;
});
</script>
Create a scoped variable that indicated whether or not it is collapsed . Then change that variable and the ng-shows will react.

ng-click not firing $scope.doSomething(), onclick for same function works

The controller I'm using is:
angular.module('app.PostView', [])
.controller('PostViewCtrl', function($scope, $http, Constants) {
$scope.posts = [];
$scope.doSomething = function(){
console.log("in doSomething");
}
$http.get(Constants.POST_URL)
.then(function (response){
console.log(response);
var post = new PostFactory(response.data);
$scope.posts.push(post);
});
})
The view for the controller is
<div ng-repeat="post in posts" >
<div class="home-container">
<div id="details-container">
<!-- using single item Array instead of single iftem to fix linkify bug -->
<div ng-bind="post.desc"></div>
<span class="item-note single-post-details">
<!-- <div class="time-text">{{post.id}}</div> -->
<div class="title" >{{post.title}}</div>
</span>
<a ng-click="doSomething()" href="#" >{{post.name}}</a>
</div>
</div>
</div>
If I replace ng-click with onclick then doSomething is triggered. Currently it is not. The same Controller and html code in other controller/views does work.
When you clicking on the anchor, it change the routing as http://url/#, that listen by the $routeProvider & ng-view loads the default view and template as you are seeing on your side.
Basically you need to remove href="#" from your anchor link or just put href="" blank in that anchor. That would fix your problem.
<a ng-click="doSomething()" href="" >{{post.name}}</a>
Remove href completely
<a ng-click="doSomething()"
style='cursor:pointer' >{{post.name}}</a>

How to toggle a glyphicon icon class?

I am working with AngularJs, Bootstrap 3. I want to toggle my glyphicon icon on my page. But i am able to do it. I followed the response at the stackoverflow question here.
I don't understand why i cannot display glyphicon with the toggle expression.
Here is my code :
<script>
angular.module("myapp", [])
.controller("MyController", function($scope) {
$scope.toggleIcon = false;
$scope.sort = function (sortBy) {
$scope.toggleIcon = !$scope.toggleIcon;
// sorting logic
};
} );
</script>
</head>
<body ng-app="myapp">
<div ng-controller="MyController" >
<div class="row">
Here the name to sort
Name <span class="glyphicon" ng-class="{glyphicon-sort-by-alphabet': toggleIcon, 'glyphicon-sort-by-alphabet-alt': !toggleIcon}"></span>
</div>
<div class="row">
Here the icon
<span class="glyphicon glyphicon-sort-by-alphabet"></span>
</div>
</div>
</body>
</html>
You can see the code on Plunker
Thank you.

Categories