I am an angular beginner & trying to introduce angular in a legacy application. The page structure looks like this
<html ng-app="demoApp">
<div class="static-parent">
<div class="dyanamic" ng-controller="SimpleController">
<ul>
<li ng-repeat="cust in customers">
{{cust.name}} - {{cust.city}}
</li>
</ul>
</div>
</div>
</html>
The "dyanamic" div is added to dom when a certain button is clicked.
As this controller div is being added dynamically, i tried to load angular afterwards by calling angular bootstrap
angular.bootstrap(document,['demoApp']);
After running the above statement,
3 Li elements are getting created in the dom
But no data is being seen
on the web page. The Li elements are empty
>> angular.element(".dynamic").scope().customers; returns 3 customer objects as expected.
>> angular.element(".dynamic").scope().$apply(); did not help either.
Can you please suggest where I am going wrong? Tried other answers on stackoverflow but didn't seem to help.
Controller code:
//setting up controller
var demoApp = angular.module("demoApp", []);
var controllers = {};
controllers.SimpleController = function($scope){
$scope.customers = [{name:'dave', city:'auckland'},{name:'abe', city:'City2'}, {name:'ram', city:'City3'}];
};
demoApp.controller(controllers);
Code for adding the div dynamically:
var template = Handlebars.compile( $("#template-content-content-container").html() );
$("static-parent").html(template(data));
angular.bootstrap('.page .row', ['demoApp']);
Angular version: 1.0.6
On 1.2.28, calling angular.bootstrap(document,['demoApp']) or angular.bootstrap('.dynamic',['demoApp']);`
is giving
Error: error:btstrpd
App Already Bootstrapped with this Element
Following is the browser screenshot -
Please, check the third (accepted) answer to this: Angular bootstrapping after load of html
(direct link: Loading an AngularJS controller dynamically)
I think, you have to "compile" anything, which is added after a first 'bootstrap' call
Also, I've made this fiddle yesterday to describe my trouble, I think it fits yours.
http://jsfiddle.net/21neg0ox/
var app = angular.module('app', []);
angular.element(document).ready(function () {
angular.bootstrap(document, ['app']);
});
//c1
app.controller('c1', ['$scope', '$compile', c1Fn]);
app.controller('c2', ['$scope', '$compile', c1Fn]);
function c1Fn($scope){
$scope.isAlive = 'is alive';
}
setTimeout(wtf, 500);
function wtf(){
var myLovelyHTML = '<div ng-controller="c2">c2 {{isAlive}}</div>';
document.getElementById('c2-wrap').innerHTML = myLovelyHTML;
}
Related
Basically I want to achieve like this scenario:
https://i.stack.imgur.com/LLTcK.png
My research led me to $compile, $trustAsHtml,at last directive.
In $compile and $trustAsHtml I can only append static template or only html but can't use dynamic things such ui-sref, ng-click etc.
So, I tried to create directive it is not working and also I am unable to add multiple template on click.
controller :
app.controller('Ctrl', ['$rootScope', '$scope',function ($rootScope, $scope)
{
$rootScope.enableDirective=false;
if(userHasOneApp){// checking some at least one app then only do action
$rootScope.appicon="img_url"; // data which i am passing
$rootScope.appname="App_name"; // data which i am passing
$rootScope.enableDirective=true;
}
}]);
custom directive:
app.directive('headerTemplate', function () {
return {
template:'<a ui-sref="/event" ng-click="editIt()">'
+'<img src="{{appicon}}"></a>'
+'<span>{{appname}}</span>',
scope:{
appname:'=',
appicon:'='
}
};
});
Header view :
<div> class="headerdiv">
<ul ng-if="enableDirective">
<li header-template appicon="appicon">
</li>
</ul>
</div>
Main view :
<div> class="maindiv">
<ui-view></ui-view> <!--basically I want to append template here -->
<button>Add next template</button>
</div>
Where I am doing wrong ?
Well i was facing the same issue
Check out the following link
This will surely help you.
I have implemented this and it worked in my scenario where i wanted to serve a directive when required i.e Lazy Loading of directive
https://www.codeproject.com/Articles/838402/Lazy-loading-directives-in-AngularJS-the-easy-way
Does Angularjs provide any method that can traverse the DOM for text after a new view is returned? The filter seems to almost accomplish this but I'm not looking to return a new array of elements. For example;
html
<div ng-view="">
<ul>
<li>Milk</li>
<li>Eggs</li>
<li>Cheese</li>
</ul>
</div>
js
$(document).ready(function() {
var app = angular.module('app', ['ngRoute'])
.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/', { templateUrl: 'example.html' })
}]);
app.controller('rttController', function($scope, $location) {
$scope.$on('$locationChangeSuccess', function(event) {
// Search through the DOM for text returned in this view
});
});
My end goal is to have an array of predefined keywords that I'd be searching for in the DOM:
var foods[] = {"yogurt", "butter", "margarine"} .
Any ideas?
No it doesn't provide this functionality. Is it not possible to load the variables into an array and loop through that. The using ng-repeat you can display them on the page in your list.
Are you limited to having these items in HTML or would you be able to load them into an array and display them?
Maybe you could look into child scopes and having a controller within the HTML file you are including to manage the list?
In my AngularJs Project I have a DIV tag which contains the main navigation bar in my project.
This navigation bar has it's own specific controller which called "topNavController".
I've recently modified my app in order to load everything -somehow- lazily using RequireJs .
The problem is this controller is not dependant on any view/route and has to be loaded directly after my App.js loads .
I'm bootstrapping my app from my RequireJs main file using :
angular.bootstrap(document, ['myApp']);
If I do like :
<div ng-controller="topNavController">...</div>
I get an error which says :
Argument 'topNavController' is not a function, got undefined
which I think it's because myApp is not bootstrapped at the moment Angular tries to bind this controller to my DIV.
I appreciate any suggestions, workarounds or solutions for this.
Thanks in advance.
You miss ng-app to launch the angular bootstrap method.
<div ng-app="myApp">
<div ng-controller="topNavController"></div>
</div>
You should use directive for this behavior
I've fixed it by removing
ng-controller='topNavController'
and making a directive for it, I put all the code from topNavController to topNavDirective and used directive's controller instead.
Thanks to "iScor" hint in the answer above !
here is how the last version of my main RequireJs file looks like :
require(
[
'app',
'routeResolver',
'services/authService',
],
function () {
require(["directives/topNavDirective"]);
angular.bootstrap(document, ['myApp']);
});
Suppose that I've written a web page that requires the user to key in data into forms. Suppose that there are two parts of the page that are completely separate in the DOM, yet are logically related. I need to bind them to a single model.
The first (bad) solution I can think of is to completely restructure the page so that everything to be bound to the model is contained in a single <div> element (or perhaps even put the controller on the <body> element).
Another solution might be to bind the inputs to a object that could be made a member of two different controllers, but that sounds like a bit of a kludge.
Suppose the HTML looks like this:
<input ng-model='data1' />
<div>
<!-- something complicated -->
</div>
<input ng-model='data2' />
You can create a shared service and inject into both controllers. This can be achieved by either the factory or service pattern. See SO post angular.service vs angular.factory for some insight on the difference/similarity between the two.
This is the Angular way to do this. See the AngularJS services docs for more information. A simple example may include...
<div ng-app="app">
<div ng-controller="ctrlA"></div>
<div ng-controller="ctrlB"></div>
</div>
app.service('sharedService', [function () {
this.someValue = 'yo!'
}]);
app.controller('ctrlB', ['$scope', 'sharedService', function($scope, sharedService) {
console.log(sharedService.someValue) // yo!
}]);
app.controller('ctrlA', ['$scope', 'sharedService', function($scope, sharedService) {
console.log(sharedService.someValue) // yo!
}]);
JSFiddle Link
I have noticed in a few tutorials and code examples floating around the internet developers using a global AppController in their applications and modules.
Is it best practice to create a global AppController in AngularJS?
I do see some benefits such as being able to handle events in a "global" scope such as:
app.controller('AppController', function($scope, $rootScope, $route, $location){
$rootScope.$on('$routeChangeStart', function(event, current, previous) {
console.log('Do something...');
});
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
console.log('Do something...);
});
});
are there any other advantages or disadvantages to this pattern?
Purely in context of situation. Let's take an example of dynamically changing title tags and page view:
.config(['$routeProvider','$locationProvider',function($routeProvider,$locationProvider){
$routeProvider.when('/', {
template: '/views/home.html',
title:'Home'
});
$locationProvider.html5Mode(true);
}]);
.controller('app', ['$scope','$route','$location',function($scope,$route,$location){
$scope.$on("$routeChangeSuccess",function($currentRoute,$previousRoute ){
$scope.title = $route.current.title;
$scope.page = $route.current.template;
});
}]);
Now both our title and page view are being dynamically loaded in through app level controller that wraps our application. This can be very useful.
<html lang="en" ng-controller="app">
<head>
<title>{{title}}</title>
</head>
<body>
<ng-include src="page"></ng-include>
</body>
</html>
Here's an example of when not to use it. Let's say one of our partial pages return data from an API:
<!-- search.html -->
<div ng-repeat="item in items">
{{item.title}}
</div>
And in our app level controller we are pulling data via broadcast:
$scope.$on('searchComplete',function(d){
$scope.items = d
});
That partial will show the data as we intended however - problems could arise when other child partials use items where scope is being overwritten.
<!-- other-search.html -->
<div ng-controller="OtherSearch" ng-click="search()">
<div ng-repeat="item in items">
{{item.title}}
</div>
</div>
In this partial, ng-click is guiding the users request. So if the app level controller already binded items in the parent, the user will see a list of items when toggling to this partial even if they never triggered the action of search().