Having an issue with trying to pass some scope data from my app controller to directive
http://plnkr.co/edit/github:plnkr/starters/v1.4.0/templates/angularjs?open=lib%2Fscript.js&deferRun=1&preview
(function () {
'use strict';
angular
.module('app', [])
.controller('HomeCtrl', ['$http', '$scope', HomeCtrl])
.directive('services', [
function () {
return {
restrict: 'E',
scope: {
testData: '='
},
template:
'<h2 class="service-name">Test: {{testData}}</h2>'
};
}
]);
/**
* Home controller.
* #param {*} $scope
*/
function HomeCtrl($http, $scope) {
$scope.testData = 'name';
}
})();
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="lib/style.css" />
<script src="lib/script.js"></script>
</head>
<body ng-app="app">
<div ng-controller="HomeCtrl">
<services testData="testData"></services>
</div>
</body>
</html>
I'm getting undefined for the scope "=" variable, testData
I can get it to render in the app using {{testData}}, but when passing it as an attribute, the directive is not receiving the value.
Here is your show code example modify to pass scope data to directive.
(function () {
'use strict';
angular
.module('app', [])
.controller('HomeCtrl', ['$http', '$scope', HomeCtrl])
.directive('services', [
function () {
return {
restrict: 'E',
scope: {
testData: '#testData' // ****************** note here
},
template:
'<h2 class="service-name">Test: {{testData}}</h2>'
};
}
]);
/**
* Home controller.
* #param {*} $scope
*/
function HomeCtrl($http, $scope) {
$scope.testData = 'name';
}
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="HomeCtrl">
<!-- // ****************** note here -->
<services test-Data="Hello World!"></services>
</div>
</body>
Related
Property Binding | AngularJS
We were trying to use property binding in AngularJS Directives,but the problem raised the error stated as
The controller with the name counterController is not registered.
We would like to pass the variable:firstcount from counterController to orderController. The variable:firstcount needs to be increment/decrement on click of a button.
Can someone help us resolve the error?
app.js
(function(){
'use strict';
angular
.module('mainApp', []);
}());
index.html
<!DOCTYPE html>
<html ng-app="mainApp">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="angular.min.js"></script>
</head>
<body>
<div ng-controller='counterController as counter'>
<counter count="counter.firstcount"></counter>
</div>
<script src="app.js"></script>
<script src="counterController.js"></script>
<script src="orderController.js"></script>
<script src="counter.directive.js"></script>
</body>
</html>
orderController.js
(function () {
'use strict';
angular.module('mainApp', [])
.controller('orderController', orderController);
orderController.$inject = ['$scope'];
function orderController($scope) {
this.count=$scope.count;
console.log("Inside OrderController");
this.increment = function () {
this.count++;
}
this.decrement = function () {
this.count--;
}
};
}());
counterController.js
(function () {
'use strict';
angular.module('mainApp', [])
.controller('counterController', counterController);
counterController.$inject = ['$scope'];
function counterController($scope) {
var counter = this;
counter.firstcount = 10;
console.log("Inside Counter Controller");
counter.increment=function(){
counter.count++;
}
counter.decrement=function(){
counter.count--;
}
};
}());
counter.directive.js
(function () {
'use strict';
function counter() {
return {
restrict: 'E',
scope: {
count: '='
},
controller: 'orderController as order',
template: `
Counter: <input type="text" ng-model="order.count">
<button type="button" ng-click="order.increment()">Increment</button>
<button type="button" ng-click="order.decrement()">Decrement</button>
`
};
}
angular.module('mainApp')
.directive('counter', counter);
}());
You continue to define the app module so instead of doing this everytime:
angular.module('mainApp', [])
Do this instead:
angular.module('mainApp')
You actually do follow that pattern in your counter.directive.js. You should only have:
angular.module('mainApp', [])
Once in your app, in the app.js file likely.
Delete the dependency argument in the controller definitions:
(function () {
'use strict';
̶a̶n̶g̶u̶l̶a̶r̶.̶m̶o̶d̶u̶l̶e̶(̶'̶m̶a̶i̶n̶A̶p̶p̶'̶,̶ ̶[̶]̶)̶
angular.module('mainApp')
.controller('orderController', orderController);
Beware that using angular.module('myModule', []) will create the module myModule and overwrite any existing module named myModule. Use angular.module('myModule') to retrieve an existing module.
— AngularJS Developer Guide - modules
For more information, see
AngularJS Error Reference - Error: $controller:ctrlreg
Controller is not registered error after adding ngRoute `.config`
I have a question about how to pass scope to a template rendered from a directive. This seems like it should be so straight forward but somehow I am having a lot of trouble getting it to work.
My HTML (simplified for brevity) is as follows:
<div ng-app="myApp">
<md-content>
<!-- strangely TestController as tc doesnt work -->
<div ng-controller="TestController">
<div ng-click="showDialog();">Show</div> <!-- this also doesnt seem to work.. -->
</div>
</md-content>
</div>
And then the application (contained in a script tag on index.html):
// app -- using components
var app = angular.module('ctrlApp',
['components', 'ngMaterial']);
// removed app.config from ngMaterial for brevity
The app contains a controller that has a function to show a mdDialog:
//controller
app.controller('TestController', function($scope, $log, $mdDialog) {
$scope.items = [{'title': 1},{'title': 2}];
// open modal
$scope.showDialog = function() {
$mdDialog.show({
templateUrl: 'dialog.html',
parent: angular.element(document.body),
clickOutsideToClose:true,
controller: function() {
// scope from parent persists here as expected
console.dir($scope.items);
// used to wire up dialog specific UI behavior
$scope.cancel = function() { $mdDialog.hide(); }
}
});
};
});
Dialog.html just renders out the directive in a modal:
<md-dialog aria-label="test">
<form ng-cloak>
<!-- rendering a directive here -->
<my-directive></my-directive>
</form>
</md-dialog>
And finally, returning back to the app, here is the directive:
// link up a directive that is rendered in the model form
var d = angular.module('components', []);
d.directive('myDirective', function() {
function link(scope, element, attributes ) {
console.log("scope.items are ", scope.items); }
return({
restrict: "E",
controller: 'TestController',
link: link,
templateUrl: 'directive.html',
});
});
And finally the directive.html template:
<div>
<h1>my Directive template</h1>
<pre> Empty!: {scope.items}</pre>
</div>
I am confused as to how I can get the scope that is created by the TestController into the template that is rendered by the directive. It works fine all the way up to the 'link' function but not in the directive's template...
Any advice would be much appreciated!
Thanks
- X
You have done mistake in directive.html,
Your code:
<div>
<h1>my Directive template</h1>
<pre> Empty!: {scope.items}</pre>
</div>
Expected code:
<div>
<h1>my Directive template</h1>
<pre> Empty!: {{scope.items[0]}}</pre> //Here you need to pass Array index
</div>
Here i given you running code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="bower_components/angular-material/angular-material.min.css" media="screen" title="no title" charset="utf-8">
<script src="bower_components/angular/angular.min.js" charset="utf-8"></script>
<script src="bower_components/angular-animate/angular-animate.min.js" charset="utf-8"></script>
<script src="bower_components/angular-aria/angular-aria.min.js" charset="utf-8"></script>
<script src="bower_components/angular-messages/angular-messages.min.js" charset="utf-8"></script>
<script src="bower_components/angular-material/angular-material.js" charset="utf-8"></script>
</head>
<body>
<div ng-app="ctrlApp">
<md-content>
<!-- strangely TestController as tc doesnt work -->
<div ng-controller="TestController">
<div ng-click="showDialog();">Show</div>
<!-- this also doesnt seem to work.. -->
</div>
</md-content>
</div>
<script type="text/javascript">
/** Own Module **/
var d = angular.module('components', []);
d.directive('myDirective', function() {
function link(scope, element, attributes) {
console.log("scope.items are ", scope.items);
}
return ({
restrict: "E",
controller: 'TestController',
link: link,
template: '<div>\
<h1>my Directive template</h1>\
<pre> Empty!: {{items[0]}}</pre>\
</div>',
});
});
var app = angular.module('ctrlApp', ['components', 'ngMaterial']);
app.controller('TestController', function($scope, $log, $mdDialog) {
$scope.items = [{
'title': 1
}, {
'title': 2
}];
// open modal
$scope.showDialog = function() {
$mdDialog.show({
template: '<md-dialog aria-label="test">\
<form ng-cloak>\
<my-directive></my-directive> </form>\
</md-dialog>',
parent: angular.element(document.body),
clickOutsideToClose: true,
controller: function() {
// scope from parent persists here as expected
console.dir($scope.items);
// used to wire up dialog specific UI behavior
$scope.cancel = function() {
$mdDialog.hide();
}
}
});
};
});
</script>
</body>
</html>
If you want to pass the scope to template try something like this
In Dialog.html
In Directive just add the following line
return({
restrict: "E",
controller: 'TestController',
scope:{
item:'='
},
link: link,
templateUrl: 'directive.html',
});
Hope this helps.
If you want to pass scope to $mdDialog look at the link below.
https://github.com/angular/material/issues/1531
I'm trying to inject my factory into a controller. If I list the factory as one of the controller's parameters, I get this error:
Error: [$injector:unpr] Unknown provider: wordRushFacProvider <- wordRushFac <- wordrushCtrl
http://errors.angularjs.org/1.6.1/$injector/unpr?p0=wordRushFacProvider%20%3C-%20wordRushFac%20%3C-%20wordrushCtrl
Here is the code for my factory:
(function() {
"use strict";
angular
.module("wordrush")
.factory("wordRushFac", function($http) {
function getValidWords() {
return $http.get('../data/valid-words.txt');
}
return {
getValidWords : getValidWords
}
})
})
And the code for my controller:
(function() {
'use strict'
angular
.module('wordrush')
.controller('wordrushCtrl', function($scope, $http, wordRushFac) {
wordRushFac.getValidWords().then(function(words) {
$scope.words = words.data;
});
$scope.words = 'Hello'
});
})();
And for my index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Word Rush</title>
<link rel="stylesheet" href="node_modules/angular-material/angular-material.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
<script src="node_modules/angular/angular.js"></script>
<script src="scripts/app.js"></script>
<script src="components/wordrush.ctr.js"></script>
<script src="components/wordrush.fac.js"></script>
</head>
<body ng-app="wordrush" ng-controller="wordrushCtrl">
<h1> {{ words }} </h1>
</body>
</html>
And for my app.js:
angular
.module('wordrush', ['ngMaterial'])
.config(function($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('blue')
.accentPalette('green');
})
I made a program with code identical to this except the names and variables were changed, and it worked fine. So what am I doing wrong here?
Here is a plunkr that says "Hello": https://plnkr.co/edit/MyxcXQ8YI4QYqeFsyVJz?p=preview
You have an extra set of open / close parenthesis in your controller definition, remove those:
angular
.module('wordrush')
.controller('wordrushCtrl', function($scope, $http, wordRushFac) {
wordRushFac.getValidWords().then(function(words) {
$scope.words = words.data;
});
$scope.words = 'Hello'
});
Also, are you sure you are including the ng-material JS file? I didn't see that listed in your HTML.
You're not injecting in the controller, should be:
.controller('wordrushCtrl', ['$scope', '$http', 'wordRushFac', function($scope, $http, wordRushFac) {
// Rest of controller code;
}]);
Switch your scripts. Factory script should be first then controller
Ther order should be,
<script src="scripts/app.js"></script>
<script src="components/wordrush.fac.js"></script>
<script src="components/wordrush.ctr.js"></script>
DEMO
I made the following changes and it worked fine.
(function() {
"use strict";
angular
.module("wordrush")
.factory("wordRushFac", function($http) {
function getValidWords() {
return $http.get('../data/valid-words.txt');
};
return {
getValidWords : getValidWords
};
});
}());
i'm using JHispter and i saw that uses these AngularJS rules: https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md
Using IIFE,Getters,Use Strict, Named Functions,ControllerAs,etc i would like to create a simple page that parse a JSON and show a movie list (title, director,duration) and the one that lasts much longer.
I've searched and tried all day but nothing works. The factory can't be used in the controller tough i inject it using $inject.
That's my index.html
<html>
<head>
<title>Hello Angular</title>
<link href="stile.css" rel="stylesheet" type="text/css">
<link rel="shortcut icon" href="">
</head>
<body ng-app="myApp">
<h1>Hello Angular</h1>
<div ng-controller="myController as sc">
<h1>angular JSON test</h1>
<!-- <p>Print movie list</p>
<ul >
<li ng-repeat="film in sc.elencoFilm">
{{film.title}}, {{film.director}}, {{film.time}}
</li>
</ul>
<p >Trova il film più lungo: {{sc.maxTimeFilm().title}} </p> -->
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="JS/app.config.js"></script>
<script src="JS/app.state.js"></script>
<script src="JS/app.service.js"></script>
<script src="JS/app.controller.js"></script>
</body>
</html>
My app.config.js
(function() {
'use strict';
angular
.module("myApp", []) ;
})();
My app.state.js
(function() {
'use strict';
angular
.module('myApp')
.config(stateConfig);
stateConfig.$inject = ['$routeProvider'];
function stateConfig($routeProvider) {
$routeProvider.when('/', {
templateUrl:"index.html",
controller:"serverController"
});
}
})();
My app.controller.js
(function () {
'use strict';
angular
.module("myApp",[])
.controller("myController", myController);
//myController.$inject = ['$scope', '$http'];
myController.$inject = ['$scope', '$http','myFactory'];
function myController($scope, $http, myFactory) {
//function myController($scope, $http){//, myFactory) {
var vm = this;
var elencoFilm={};
myFactory.getMovies().then(function (response) {
vm.elencoFilm = response;
});
vm.maxTimeFilm = getMaxTimeFilm();
function getMaxTimeFilm() { //return the longest film
}
}
})();
My app.service.js
(function () {
'use strict';
angular.module('myApp',[])
.factory('myFactory', myFactory);
myFactory.$inject = ['$scope', '$http','myFactory'];
function myFactory($scope, $http) {
console.log("sono nella factory");
return {
getMovies: function ($http) {
return $http.get('https://api.myjson.com/bins/1bgtg3');
/* .then(function (response) {
return response.data.movies;
});*/
}
}
}
})();
it always return this error:
https://docs.angularjs.org/error/$injector/unpr?p0=myFactoryProvider%20%3C-%20myFactory%20%3C-%20myController
it can't recognize myFactory into myController function!
in app.controller.js this line
function myController($scope, $http, myFactory) {
this break out the error!
Thank you for the help!! :)
Do not add empty dependency array in for module myApp in controller and factory.
Use .module('myApp') in both controller and factory, similar to your config.
By defining your modules based on functionality the myFactory service should be under a encapsulated closure referencing the main app module, hence all your factories can go under this module (ex. factories.module.js) :
(function() {
'use strict'
angular.module('myApp.factories', []);
}();
Once that module is added to your app.config
(function() {
'use strict'
angular.module('myApp', [
'myApp.factories'])
})();
It separates the concerns of your modules based on functionality following the IIFE design principle. Now reference your new module to myFactory in your service file.
(function () {
'use strict'
angular.module('myApp.factories')
.factory('myFactory', myFactory)
...
I've solved it!
i simply removed $scope from factory and removed [] in the controller definition (.module("myApp") insted of .module("myApp",[]) ).
#23rharris your advice is a best practice?
I've used the factory in each function of the controller every time i needed the JSON file :
myController.$inject = ['$scope', 'myFactory'];
function myController($scope, myFactory) {
...
vm.elencoFilm = getMovies();
function getMovies() {
myFactory.getMovies().then(function (response) {
...
...
vm.maxTimeFilm =getMaxTimeFilm();
function getMaxTimeFilm() {
myFactory.getMovies().then(function (response) {
if (response.data.movies != undefined) {
...
Is this the correct pattern for REST?
i am familiar with the syntax of controller & name but i'm trying to create a generic directive that will get a list of items and for each item i need to specify a controller.
This is my main directive:
function controlPanel() {
var directive = {
restrict: 'E',
replace: true,
scope: {
controlPanelItems: "=sbControlPanelItems"
},
templateUrl: 'control-panel.html',
link: link
};
return directive;
function link(scope, element) {
}
}
Here is the directive template:
<sb-control-panel-item ng-repeat="controlPanelItem in controlPanelItems"
sb-title="controlPanelItem.title"
sb-template-url="controlPanelItem.templateUrl"
sb-control-panel-item-controller="controlPanelItem.controller"></sb-control-panel-item>
My issue is with the sb-control-panel-item-controller attribute.
Angular throws exception when i'm passing variable, it work's great when i'm passing simple string (the name of the controller).
Here is the code of the control-panel-item directive:
function controlPanelItem() {
var directive = {
restrict: 'E',
replace: true,
scope: {
title: '=sbTitle',
templateUrl: '=sbTemplateUrl'
},
templateUrl: 'control_panel_item.html',
controller: '#',
name: 'sbControlPanelItemController',
link: link
};
return directive;
function link(scope, iElement, iAttributes, controller) {
}
}
Maybe there is a way to inject the controller through the link function and then i'll just pass it through the scope?
You can use the $controller service to instantiate whatever controller dynamically inside the directive, check this plunkr.
Just bear in mind that if you wanted to specify a controller statically now, you would need to enclose it in single quotes.
Basically the code would be like:
function MainCtrl() {
this.firstCtrl = 'FirstCtrl';
this.secondCtrl = 'SecondCtrl';
}
function FirstCtrl() {
this.name = 'First Controller';
}
function SecondCtrl() {
this.name = 'Second Controller';
}
function fooDirective() {
return {
scope: {
ctrl: '='
},
template: '<div>{{foo.name}}</div>',
controller: ['$controller', '$scope', function($controller, $scope) {
var foo = $controller($scope.ctrl, {$scope: $scope});
return foo;
}],
controllerAs: 'foo',
link: function ($scope, $element, $attrs, $ctrl) {
console.log($scope.ctrl);
}
};
}
angular
.module('app', [])
.directive('fooDirective', fooDirective)
.controller('MainCtrl', MainCtrl)
.controller('FirstCtrl', FirstCtrl)
.controller('SecondCtrl', SecondCtrl);
and this would be the HTML
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.5.8" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="MainCtrl as main">
<h1>
Test
</h1>
<foo-directive ctrl="main.firstCtrl">
"name: " {{foo.name}}
</foo-directive>
<foo-directive ctrl="main.secondCtrl">
{{foo.name}}
</foo-directive>
</body>
</html>
========================================================================
WRONG OLD ANSWER
From this blog entry seems to be an undocumented property that allows you to do exactly what you need.
function FirstCtrl() {
this.name = 'First Controller';
}
function SecondCtrl() {
this.name = 'Second Controller';
}
function fooDirective() {
return {
scope: {},
name: 'ctrl',
controller: '#',
controllerAs: 'foo',
template: '<div></div>',
link: function ($scope, $element, $attrs, $ctrl) {
}
};
}
angular
.module('app', [])
.directive('fooDirective', fooDirective)
.controller('FirstCtrl', FirstCtrl)
.controller('SecondCtrl', SecondCtrl);
So all you need to do in your directive is add a property name linked to the attribute you will use with the name of your controller.
<foo-directive ctrl="FirstCtrl"></foo-directive>
<foo-directive ctrl="SecondCtrl"></foo-directive>
If your directive, as per your question, needs to be from a property rather than a string, use {{}} notation:
<sb-control-panel-item ng-repeat="controlPanelItem in controlPanelItems"
sb-title="controlPanelItem.title"
sb-template-url="controlPanelItem.templateUrl"
sb-control-panel-item-controller="{{controlPanelItem.controller}}"></sb-control-panel-item>