AngularJS compile dynamic content - angularjs

Consider the following webpage:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>First Test</title>
<script src="jquery-3.2.1.min.js"></script>
<script src="angular.js"></script>
<script>
var myApp = angular.module('myApp',[]);
function addDiv(){
var div = "<script> \
myApp.controller('myController', function ($scope) { \
$scope.testDynamic = function(){ \
alert('it works!'); \
} \
}); \
<\/script> \
<div ng-controller=\"testController\">{{\"TEST\"}}<button ng-click=\"testDynamic();\">Click Me!</button></div>";
$("body").append(div);
// How to use $compile here???
}
</script>
<link href="bootstrap.css" rel="stylesheet" />
<link href="bootstrap-theme.css" rel="stylesheet" />
</head>
<body>
<div>{{"AngularJS"}}</div>
<button onclick="addDiv();">addDiv</button>
</body>
</html>
When the content is appended to the body, how I can load/compile the angularjs part? I have tried to use $compile like:
angular.element('body').injector().invoke(function ($compile, $rootScope) {
$rootScope.$apply(function() {
var scope = angular.element(div).scope();
$compile(div)(scope);
});
});
But without any success. I get the error: "Error: [ng:areq] Argument 'scope' is required..."
Someone can help?

After some tries, I got it working. It was simpler than I thought. After the definition of angular module, I need to add this configuration part:
myApp.config(['$controllerProvider','$compileProvider', '$filterProvider', '$provide', function($controllerProvider, $compileProvider, $filterProvider, $provide) {
myApp.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
Then to register the controller coming from ajax:
myApp.register.controller('myController', function($scope) {
$scope.name = "Pippo";
$scope.age = 18;
$scope.go = function(){alert('It works!')}
});
Then, at the success call from ajax add the compile part:
$compile($('#remdiv'))($scope);
Here's the complete code:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>First Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script>
myApp = angular.module('myApp',[])
.controller("mainCtrl", function($scope, $http, $compile, $rootScope){
$scope.addDiv = function(){
var ajaxhtmlcode = '<script> \
myApp.register.controller(\'testc\', function($scope) { \
$scope.name="Pippo"; \
$scope.age=18; \
$scope.go = function(){alert(\'It works!\')} \
}); \
<\/script> \
<div id="remdiv" ng-controller="testc"> \
{{msg}} \
Name:<input ng-model="name" /> \
Age:<input ng-model="age" /> \
<button ng-click="go();">Go!<\/button> \
<\/div>';
$('body').append(ajaxhtmlcode);
$compile($('#remdiv'))($scope);
}
});
myApp.config(['$controllerProvider','$compileProvider', '$filterProvider', '$provide', function($controllerProvider, $compileProvider, $filterProvider, $provide) {
myApp.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
}
]);
</script>
</head>
<body ng-controller="mainCtrl">
<div>{{"AngularJS"}}</div>
<button ng-click="addDiv();">addDiv</button>
</body>
</html>

1- First of all you have incorrect controller naming, you inject a controller named myController but you trying to call controller named testController
2- you can't declare new controller with this way you have to declare it first and inject the template only via compile method
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>First Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>
var myApp = angular.module('myApp',[])
.controller("mainCtrl",function($compile,$scope,$rootScope){
$scope.addDiv=function(){
var div = $compile("<div ng-controller=\"test\">{{\"TEST\"}}<button ng-click=\"testDynamic();\">Click Me!</button></div>")($rootScope);
$("body").append(div);
// How to use $compile here???
}
})
.controller('test', function ($scope) {
$scope.testDynamic = function(){
alert('it works!');
}
});
</script>
<link href="bootstrap.css" rel="stylesheet" />
<link href="bootstrap-theme.css" rel="stylesheet" />
</head>
<body ng-controller="mainCtrl">
<div>{{"AngularJS"}}</div>
<button ng-click="addDiv();">addDiv</button>
</body>
</html>

Thank you Peter. The first was a copy-paste mistake. I am new in Angular and I am just trying to understand how it works. Your solution works, but what I wanted to point our is this:
What about if I can't define the controller "test" BEFORE? I mean, if the controller definition comes from a html ajax request (I mean if the div variable is populate by an ajax request, controller definition included). That's why I have put the script definition inside the div variable.
Taking back my example...main page:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<title>First Test</title>
<script src="jquery-3.2.1.min.js"></script>
<script src="angular.js"></script>
<script>
var myApp = angular.module('myApp',[])
.controller("mainCtrl",function($compile,$scope,$rootScope, $http){
$scope.addDiv=function(){
$http({
url: "test.php",
method: "post",
data: '',
responseType: 'text',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function successCallback(response) {
$('body').append(response.data);
}, function errorCallback(response) {
alert(response.statusText);
});
}
});
</script>
<link href="bootstrap.css" rel="stylesheet" />
<link href="bootstrap-theme.css" rel="stylesheet" />
</head>
<body>
<div ng-controller="mainCtrl">{{"AngularJS"}}
<button ng-click="addDiv();">addDiv</button>
</div>
</body>
</html>
Where test.php is simply:
<script>
myApp.controller('myController', function ($scope) {
$scope.name = "Pippo";
$scope.age = 10;
});
</script>
<div ng-controller="myController">
Name:<input ng-model="name" />
Age:<input ng-model="age" />
</div>
If I run this code, I can't see the input (name and age) populated as defined in "myController"...

Related

Angular Controller is not triggering

My controller is not triggering. It should be stupid but I can't see why.
Here find my code structure.
Please help me find that basic error.
template :
<!DOCTYPE html>
<html ng-app="attachmentsApp" ng-cloak="">
<head>
<meta charset="utf-8"/>
<script th:inline="javascript">
/*<![CDATA[*/
var source = [[${source}]];
var appContext = /*[[#{/}]]*/ '';
/*]]>*/
</script>
</head>
<body>
<div th:replace="include"></div>
<script th:src="#{/app/modules/attachments/scripts/attachmentsapp.js}"></script>
<script th:src="#{/app/modules/attachments/scripts/controllers/AttachmentsHomeCtrl.js}"></script>
<script th:src="#{/app/modules/attachments/scripts/services/AttachmentsHomeService.js}"></script>
</body>
</html>
App :
angular
.module('attachmentsApp', ['ngRoute'
]).run(['$rootScope', function($rootScope){
$rootScope.appContext = window.appContext;
$rootScope.language = window.language;
$rootScope.source = window.source;
}])
.config(function($routeProvider) {
$routeProvider.when('/', { templateUrl: window.appContext + 'app/modules/attachments/views/home.html', controller: "AttachmentsHomeCtrl" })
});
Controller:
angular.module('attachmentsApp').controller('AttachmentsHomeCtrl', ['$scope','$rootScope','AttachmentsHomeService','$window',
function ($scope,$rootScope,AttachmentsHomeService,$window) {
console.log($rootScope.source);
debugger;
}]);
Service :
'use strict';
angular.module('attachmentsApp').service('AttachmentsService', [ '$http', '$rootScope', function($http, $rootScope){
this.getForm = function(type) {
debugger;
}
return this;
}]);
Many thanks
Suggesting some change in your HTML:
1) Define and load files before their use: ng-app was being used before attachmentsapp.js file is loaded in DOM
2) Order of usage: service file was loaded after its usage in controller
It should be look like:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script th:inline="javascript">
/*<![CDATA[*/
var source = [[${source}]];
var appContext = /*[[#{/}]]*/ '';
/*]]>*/
</script>
<script th:src="#{/app/modules/attachments/scripts/attachmentsapp.js}"></script>
<script th:src="#{/app/modules/attachments/scripts/services/AttachmentsHomeService.js}"></script>
<script th:src="#{/app/modules/attachments/scripts/controllers/AttachmentsHomeCtrl.js}"></script>
</head>
<body ng-app="attachmentsApp" ng-cloak="">
<div th:replace="include"></div>
</body>
</html>
Not 100% sure, but it should be working. Do a try !!
Moreover, keep an eye on console.
It was the Service name.
AttachmentsHomeService as registering it in Controller
AttachmentsService in service definition
Many thanks for your help

How to use window.onload in angular js controller?

How to use window.onload function inside a controller.
window.onload= function() {
console.log("Hi Page loaded")
};
The controller is not applicable for the full page.
I want to execute a function after my controller loads at-least.
You can use ng-init and invoke your necessary function using the same directive
var app = angular.module('DemoApp', [])
app.controller('akuaController', function($scope) {
$scope.load = function() {
alert("Window is loaded");
}
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.4.7" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="DemoApp" ng-controller="akuaController">
<div ng-init="load()">
</div>
</body>
</html>
Changing the example from Angular $window
Your Controller
angular.module('windowExample', [])
.controller('ExampleController', ['$scope', '$window', function($scope, $window) {
$scope.greeting = 'Hello, World!';
$scope.doGreeting = function(greeting) {
// This would be a starting point
$window.onload(greeting);
};
}]);
Your markup
<div ng-controller="ExampleController" ng-init="ExampleController.doGreeting()">
</div>
//inside your controller
$scope.$on('$viewContentLoaded', function() {
// write here
// either methods or variables
});

Can't declare new controller - dependency missing

I'm new to AngularJS and I'm trying to declare a second controller to a new view in my page. I have a logincontroller and when I succeed the login I get to the Home.html.
When opening Home.html I get the following error below..It looks like it can't recognize my ModelController/ModalService..What am I missing here?
Error: [$injector:unpr] http://errors.angularjs.org/1.5.0-beta.1/$injector/unpr?p0=ModalServiceProvider%20%3C-%20ModalService%20%3C-%20ModalController
Index.html:
<!DOCTYPE html>
<html ng-app="PVM">
<head>
<title>My Ang</title>
<link href="Content/bootstrap.min.css" rel="stylesheet" />
<link href="Content/bootstrap-theme.min.css" rel="stylesheet" />
<link href="Content/MyCss.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
</head>
<body>
<div>
<div ng-view></div>
</div>
<script src="//code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="Scripts/bootstrap.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.1/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.1/angular-route.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.1/angular-cookies.min.js"></script>
<script src="Scripts/Services/ModalService.js"></script>
<script src="Scripts/Services/AuthenticationService.js"></script>
<script src="Scripts/Controller/LoginController.js"></script>
<script src="Scripts/Controller/ModalController.js"></script>
<script src="Scripts/MyApp.js"></script>
</body>
</html>
Home.html:
<div class="container" ng-controller="ModalController">
<div class="col-xs-2">
<button class="btn btn-group-justified" ng-init="testfunc()">press me</button>
</div>
</div>
MyApp.js:
angular.module('MyApp', [
'Authentication',
'Modal',
'ngRoute',
'ngCookies'
])
.config([
'$routeProvider', function($routeProvider) {
$routeProvider
.when('/Login', {
controller: 'LoginController',
templateUrl: 'Login.html'
})
.when('/Home', {
controller: 'ModalController',
templateUrl: 'Home.html'
})
.otherwise({
redirectTo: '/Login'
});
}
]);
ModalController.js:
angular.module('Modal')
.controller('ModalController',
['$scope', 'ModalService',
function ($scope, ModalService) {
$scope.testfunc = function() {
alert('weeee');
}
}]);
ModalService.js:
angular.module('Modal', []);
angular.module('Modal')
.factory('ModalService'
['$http',
function ($http) {
var service = {};
return service;
}
]);
You need to include app.js after including services and controllers. And controllers after services.
it should be like this:
<script src="Scripts/Services/ModalService.js"></script> <!--ModalService is being defined here -->
<script src="Scripts/Services/AuthenticationService.js"></script>
<script src="Scripts/Controller/LoginController.js"></script>
<script src="Scripts/Controller/ModalController.js"></script> <!-- ModalService is being injected here -->
<script src="Scripts/MyApp.js"></script> <!-- All of the things are set in place here -->
In fact, the best practice is to include all of them in the bottom of your <body>.
I found the answer..The problem was that I was missing a comma :(
ModalService.js should look like this:
angular.module('Modal', []);
angular.module('Modal')
.factory('ModalService', <------ COMMA MISSING :(
['$http',
function ($http) {
var service = {};
return service;
}
]);

Injecting $routeParams into controller

I'm trying to pull some data out of url to pass into a controller for use in the controller. I've been trying to do it via Angular Routing.
<!DOCTYPE html>
<html ng-app>
<head>
<meta name="viewport" content="width=device-width" />
<title>Edit</title>
<script src="~/Scripts/angular.min.js"></script>
</head>
<body>
<div ng-controller="SearchController" >
<input type="text" ng-model="SearchText" />
</div>
<script type="text/javascript">
var app = angular.module('myApp', ['ngRoute']);
app.config(function ($locationProvider, $routeProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when('/angularroute/edit/:sometext', {
controller: 'SearchController'
});
});
app.controller("SearchController", ['$scope', '$routeParams', SearchController]);
function SearchController($scope, $routeParams) {
$scope.SearchText = $routeParams.sometext;
}
SearchController.$inject = ['$scope'];
</script>
</body>
</html>
<html ng-app>
<head>
<meta name="viewport" content="width=device-width" />
<title>Edit</title>
<script src="~/Scripts/angular.min.js"></script>
</head>
<body>
<div ng-controller="SearchController" >
<input type="text" ng-model="SearchText" />
</div>
<script type="text/javascript">
var app = angular.module('myApp', ['ngRoute']);
app.config(function ($locationProvider, $routeProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when('/angularroute/edit/:sometext', {
controller: 'SearchController'
});
});
app.controller("SearchController", ['$scope', '$routeParams', SearchController]);
function SearchController($scope, $routeParams) {
$scope.SearchText = $routeParams.sometext;
}
SearchController.$inject = ['$scope'];
</script>
</body>
</html>
$routeParams in the controller is always null. Why?
Secondly, the url of the page that this is used on will be something like this: http://www.blah.com/angularroute/edit/32432 Is this an appropriate use of Angular routing?
Hi it looks like you miss reference to angular-route.js script please see example here: http://plnkr.co/edit/RZxt3t9dNQxbyW94V9jQ?p=preview
JS:
var app = angular.module('app', ['ngRoute']);
app.config(function($locationProvider, $routeProvider) {
$routeProvider
.when('/angularroute/edit/:sometext', {
controller: 'SearchController',
templateUrl: 'http://run.plnkr.co/d8ZBAv3VEkfIJI4h/search.html'
});
$locationProvider.html5Mode(true);
});
app.controller('firstCtrl', function($scope) {
});
app.controller("SearchController", ['$scope', '$routeParams', SearchController]);
function SearchController($scope, $routeParams) {
console.log($routeParams);
$scope.SearchText = $routeParams.sometext;
}
html:
<!DOCTYPE html>
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-route.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app">
<div ng-controller="firstCtrl">
Search for elephant<br/>
Search for horse<br/>
Search for tigger<br/>
</div>
<div ng-view="">
</div>
</body>
</html>
Had the same problem with AngularJS 1.3.0, updating to 1.3.13 fixed it.

sharing a var between views/controllers

I know this question has been asked 100s of times but i have yet to succeed in implementing this after reading countless of threads... shame on me.
I know this is a lot of code (sorry). But I just can't find what I'm doing wrong,
So to the problem I want to add something to the list in pat1 then click over to pat2 and see the same list.
Routing;
var routeApp = angular.module('routeApp', ['ngRoute', 'rootMod']);
routeApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/pat1', {
templateUrl: 'partials/pat1.html',
controller: 'pageOneCont'
}).
when('/pat2', {
templateUrl: 'partials/pat2.html',
controller: 'pageTwoCont'
}).
otherwise({
redirectTo: '/pat1'
});
}]);
Controllers & Service:
var rootMod = angular.module('rootMod', []);
rootMod.controller('pageOneCont', [ 'serv', '$scope', function (serv, $scope) {
'use strict';
// Your controller implementation goes here ...
$scope.handleClick = function ($scope, serv){
var updateFoo = function(){
$scope.foo = serv.foo;
};
aService.registerObserverCallback(updateFoo);
//service now in control of updating foo
};
}]);
rootMod.controller('pageTwoCont', [ 'serv', '$scope', function (serv, $scope) {
'use strict';
// Your controller implementation goes here ...
$scope.handleClick = function ($scope, serv){
var updateFoo = function(){
$scope.foo = serv.foo;
};
aService.registerObserverCallback(updateFoo);
//service now in control of updating foo
};
}]);
/* Service */
rootMod.factory('serv', [ function () {
var observerCallbacks = [];
//register an observer
this.registerObserverCallback = function(callback){
observerCallbacks.push(callback);
};
//call this when you know 'foo' has been changed
var notifyObservers = function(){
angular.forEach(observerCallbacks, function(callback){
callback();
});
};
}]);
INDEX.html
<!doctype html>
<html lang="en" ng-app="routeApp">
<head>
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
</head>
<body>
<li> ONE </li>
<li> TWO </li>
</body>
<!-- SinglePage -->
<div ng-view></div>
</html>
PAT1.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angular Test</title>
<link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="css/bootstrap.css">
<script src="lib/angular/angular.js"></script>
<script src="js/controllers.js"></script>
</head>
<div ><!--ng-app="myModule" ng-controller="ContactController">-->
<h1> ONE </h1>
<button ng-click="handleClick"> BROADCAST </button>
<div ng-repeat="item in foo">{{ item }}</div>
</div>
</html>
PAT2.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angular Test</title>
<link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="css/bootstrap.css">
<script src="lib/angular/angular.js"></script>
<script src="js/controllers.js"></script>
</head>
<div> <!--ng-app="myModule" ng-controller="ContactController">-->
<h1> TWO </h1>
<div ng-repeat="item in foo">{{ item }}</div>
</div>
</html>
JS
Your service is injected as serv in your controllers but you call aService. Use serv instead.
You should use rootMod.service() instead of rootMod.factory() since you are using this and not returning anything in your service function (see this for the difference between factories and services).
There is no serv.foo property. You have to add this.foo = /** something **/; to your service function.
So this should work:
var rootMod = angular.module('rootMod', []);
rootMod.controller('pageOneCont', [ 'serv', '$scope', function (serv, $scope) {
'use strict';
// Your controller implementation goes here ...
$scope.handleClick = function ($scope, serv){
var updateFoo = function(){
$scope.foo = serv.foo;
};
serv.registerObserverCallback(updateFoo);
// service now in control of updating foo
};
}]);
rootMod.controller('pageTwoCont', [ 'serv', '$scope', function (serv, $scope) {
'use strict';
// Your controller implementation goes here ...
$scope.handleClick = function ($scope, serv){
var updateFoo = function(){
$scope.foo = serv.foo;
};
serv.registerObserverCallback(updateFoo);
// service now in control of updating foo
};
}]);
/* Service */
rootMod.service('serv', [ function () {
var observerCallbacks = [];
// call this when you know 'foo' has been changed
var notifyObservers = function(){
angular.forEach(observerCallbacks, function(callback){
callback();
});
};
// initialize foo here
this.foo = '';
// register an observer
this.registerObserverCallback = function(callback){
observerCallbacks.push(callback);
};
}]);
HTML
You put the ng-view container outside of the body. It has to be inside. Also the path to a view starts with #/ so you have to change your links.
<!doctype html>
<html lang="en" ng-app="routeApp">
<head>
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
</head>
<body>
<li> ONE </li>
<li> TWO </li>
<!-- SinglePage -->
<div ng-view></div>
</body>
</html>
Each view only needs the content that should be placed inside the ng-view container. So you mustn't make a complete HTML document.
pat1.html
<h1> ONE </h1>
<button ng-click="handleClick"> BROADCAST </button>
<div ng-repeat="item in foo">{{ item }}</div>
pat2.html
<h1> TWO </h1>
<div ng-repeat="item in foo">{{ item }}</div>

Resources