I am trying to add another AngularJS directive to my app but for some reason it is not working. I have added other directives before in the same way but they are all working. I have posted code below.
HTML where I include the directive
<section class="section-wrap" data-ng-controller="PVProfileViewController">
<div class="container bg_white">
<div>
<pv-profile-password-reset pv-user="user"></pv-profile-password-reset>
</div>
<div>
<pv-profile-email-update pv-user="user"></pv-profile-email-update>
</div>
</div>
</section>
AngularJS directive file
'use strict';
/*
* The profile email request update section
*/
angular.module('mean.system').directive('pvProfileEmailUpdate',
['PVProfile', '$timeout', 'Global', 'Utilities',
function (PVProfile, $timeout, Global, Utilities)
{
function controller($scope)
{
$scope.global = Global;
$scope.darkout = false;
}
function link(scope, element, attrs)
{
}
return {
restrict: 'E',
templateUrl: '/path/to/profile_email_update.html',
link: link,
scope: {
user: '=pvUser'
},
controller: controller
};
}
]
);
Any ideas why this specific directive would not be working but others very similar to it would be?
Related
I've a strange behavior using multiple transclude component in Angularjs:
changes in first slot model no visible in controller.
<div ng-app="myApp" ng-controller="testController">
<script type="text/ng-template" id="component-template.html">
<div style="color:red;" ng-transclude="heading">
</div>
<div style="color:blue;" ng-transclude="body">
</div>
</script>
Example1
<input ng-model="example1Model"/>
<test-component>
<panel-heading>
Example2
<input ng-model="example2Model"/>
</panel-heading>
<panel-body>
Example1Result:{{example1Model}}<br/>
Example2Result:{{example2Model}}
</panel-body>
</test-component>
</div>
<script>
angular.module("myApp", [])
.controller("testController", function ($scope, $location) {
})
.component("testComponent", {
templateUrl: "component-template.html",
transclude: {
heading: "panelHeading",
body: "panelBody"
},
controller: function ($scope, $element, $attrs) {
this.$doCheck = function () {
//do anything
}
}
});
</script>
Now if you try to test it in this JSfiddle:https://jsfiddle.net/Lpveophe/1/
Why binding model example2Model did not working?
However example1Model binding model working correctly.
You need to use . in ng-model to make it work. For better understand of scope, please go through this article: https://github.com/angular/angular.js/wiki/Understanding-Scopes
To make it work, replace example2Model with o.example2Model everywhere and change your controller to:
.controller("testController", function ($scope, $location) {
$scope.o = {};
$scope.o.example2Model = '';
})
I have a directive that controls a personalized multiselect. Sometimes from the main controller I'd like to clear all multiselects. I have the multiselect value filling a "filter" bidirectional variable, and I am able to remove content from there, but when doing that I also have to change some styles and other content. In other words: I have to call a method belonging to the directive from a button belonging to the controller. Is that even posible with this data structure?:
(By the way, I found other questions and examples but their directives didn't have their own scope.)
function MultiselectDirective($http, $sce) {
return {
restrict: 'E',
replace: true,
templateUrl: 'temp.html',
scope: {
filter: "=",
name: "#",
url: "#"
},
link: function(scope, element, attrs){
//do stuff
scope.function_i_need_to_call = function(){
//updates directtive template styles
}
}
}
}
The best solution and the angular way - use event.
Live example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleOneController', function($scope) {
$scope.raise = function(val){
$scope.$broadcast('raise.event',val);
};
})
.controller('ExampleTwoController', function($scope) {
$scope.raise = function(val){
$scope.$broadcast('raise.event',val);
};
})
.directive('simple', function() {
return {
restrict: 'A',
scope: {
},
link: function(scope) {
scope.$on('raise.event',function(event,val){
console.log('i`m from '+val);
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="ExampleApp">
<div ng-controller="ExampleOneController">
<h3>
ExampleOneController
</h3>
<form name="ExampleForm" id="ExampleForm">
<button ng-click="raise(1)" simple>
Raise 1
</button>
</form>
</div>
<div ng-controller="ExampleTwoController">
<h3>
ExampleTwoController
</h3>
<form name="ExampleForm" id="ExampleForm">
<button ng-click="raise(2)" simple>
Raise 2
</button>
</form>
</div>
</body>
I think better solution to link from controller to directives is this one:
// in directive
return {
scope: {
controller: "=",
},
controller: function($scope){
$scope.mode = $scope.controller.mode;
$scope.controller.function_i_need_to_call = function(){}
$scope.controller.currentState = state;
}
}
// in controller
function testCtrl($scope){
// config directive
$scope.multiselectDirectiveController = {
mode: 'test',
};
// call directive methods
$scope.multiselectDirectiveController.function_i_need_to_call();
// get directive property
$scope.multiselectDirectiveController.currentState;
}
// in template
<Multiselect-directive controller="multiselectDirectiveController"></Multiselect-directive>
I need call directive function ( i need scope ) before controller.
var app = angular.module('docsRestrictDirective', []);
app.controller('Controller', ['$scope', function($scope ) {
$scope.changeDerictive();
}]);
app.directive('ngMyDer', function() {
return {
restrict: 'A',
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
scope.changeDerictive = function() {
console.log("changed");
};
}
}
}
}
});
http://plnkr.co/edit/NWb23rScg8zvPluGBWH5?p=preview
as requested this is the example with ui-router.
first we will define a controller for the base of the app.
<body ng-app="myApp" ng-controller="AppBaseCtrl">
<main role="main">
<overlay-spinner></overlay-spinner>
<invite-success></invite-success>
<div ui-view></div>
</main>
</body>
now in the ui router we will define our base route:
.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/desiredRoute');
$stateProvider
.state('desiredRoute', {
url: '/desiredRoute',
templateUrl: 'views/pathToTemplate.html',
controller: 'MyViewCtrl'
})
});
so what will happen? the base controller runs, we can initialize desired scope variables, then we run the directives and then we run our required controller.
so you have the directive which runs before the needed controller.
if we want this to be cleaner with ui-router we can define the routes like this:
in the routes config:
.state('dashboard', {
url: '/dashboard',
templateUrl: 'views/templates/dashboard/dashboard-base.html',
controller: 'DashboardBaseCtrl',
abstract: true
})
.state('dashboard.main', {
url: '/main',
templateUrl: 'views/templates/dashboard/dashboard-main.html',
controller: 'DashboardMainCtrl'
})
then in the view for the dashboard-base:
<div myDirective></div>
<div ui-view></div>
and of course define in the base controller what ever you want and as you can see... base controller runs then directive then our desired controller so directive runs before the controller...
EDIT
I have created a small plunker like you asked... you will see here that with no timeout the directive is called before our main controller does using a base controller my example is the first example in the answer
plunker with answer
Your ng-controller is written before your directive ,so if you want to call directive frist write ng-controller after your directive
like this
<body ng-app="docsRestrictDirective">
<div ></div>
<div ng-my-der></div>
<div ng-controller="Controller"></div>
</body>
Then it will show result according to you
Plunker: http://plnkr.co/edit/0qccTyPADwDaq05KKmao?p=preview
There is a priority between angularjs directives.ng-controller is directive too,try that priority.Maybe it can help you.
Thanks for answers.
I did it this way
var app = angular.module('app', []);
app.controller( "Ctrl",[ "$scope", function ( $scope ) {
$scope.$watch ( "ngExchange", function ( ) {
$scope._ngExchange[0].remove()
$scope._ngExchange[1].after( $scope._ngExchange[0] );
} );
} ] );
app.directive('ngExchange', function(){
return {
restrict: 'A',
controller: function ( $scope, $element, $attrs ) {
if ( $scope._ngExchange === undefined ) {
$scope._ngExchange = [];
}
$scope._ngExchange.push( $element );
}
}
});
http://plnkr.co/edit/fagINqNafPp6vEhawNbl?p=preview
I have a directive, form where the rest of the html is given. The directive is given below
THis is the html for directive
<div test
input="{{guage.input}}"
>
</div>
angular.module('test', [])
.directive('test', function () {
"use strict";
return {
restrict: 'A',
scope: {
input: '='
},
templateUrl: 'gauge/gauge.tpl.html',
replace: true
});
The below is the html loaded after the directive compilation.
<div ng-controller="Testing">
<div>
<div id="{{guageid}}" class="gauge ng-isolate-scope" ng-model="gauge.input" data-service="/api/getDataResult/core-mon-status" guageid="fleet_online" description="Fraction of fleet online" unit="%" test="{{gauge.test}}" input="{{gauge.input}}" gauge="">
</div>
</div>
</div>
Now I have a parent controller above this dom element name is Testing.
From my controller if I change the {{guage.input}} its not displaying.
This is my controller
app.controller('Testing',['$scope','newdataLoad','$timeout',function($scope, newdataLoad, $timeout){
$scope.gauge = {};
$scope.gauge.input = 0;
});
What is the problem with my scope here.
As your scope defines the input with = you dont need the expression brackets.
<div test input="guage.input">
Using expression brackets will break the 2-way binding.
Optimization:
You can completely move you controller into the directive and still make use of the dependency injection
"use strict";
angular.module('test', []).directive('test', function () {
return {
restrict: 'A',
scope: {
input: '='
},
templateUrl: 'gauge/gauge.tpl.html',
replace: true,
controller: function($scope, newdataLoad, $timeout){
$scope.gauge = {};
$scope.gauge.input = 0;
}
}
});
The template code then :
<div>
<div id="{{guageid}}" class="gauge ng-isolate-scope" ng-model="gauge.input" data-service="/api/getDataResult/core-mon-status" guageid="fleet_online" description="Fraction of fleet online" unit="%" test="{{gauge.test}}" input="{{gauge.input}}" gauge="">
</div>
</div>
Remove curlies:
<div test input="guage.input">
</div>
Directive in AngularJS: I find out that the elements inside an element with the directive do not inherit its "scope".
For example:
app
.controller('xxx', function($scope) {})
.directive('yyy', function() {
return {
scope: {},
link: function(scope,elem,attrs) {}
};
});
When we use it in the HTML:
<body ng-controller="xxx">
<div id='withD' yyy>
<div id='inside'>Inside the element with a directive</div>
</div>
</body>
"body" will have a scope whose $id may be 003;
then "#withD" will have an isolate scope $id=004;
the "#inside" will have the scope $id=003, which means the "#inside" inherits "body"'s scope.
If I use "transinclude" for the directive "yyy"; then "body" scope.$id=003, "#withD" scope.$id=004, "#inside" scope.$id=005; moreover, 003 has two children 004 and 005. However, I wanna make the element with the directive has an isolate scope and its child elements inherit the scope.
I read over "ui.bootstrap.tabs" source code but I do not like the style, for it is strange and also not make the parent element share its scope with child elements'; it looks like this:
app
.directive('xitem', function() {
scope: {},
controller: function($scope) {
$scope.subitem = [];
return {
add: function(xsubitem) {$scope.subitem.push(xsubitem);}
}
},
link: function(scope,elem,attrs) {}
})
.directive('xsubitem', function() {
require: '^xitem',
link: function(scope,elem,attrs,ctrl) {ctrl.add(elem);}
});
My expectation is that:
<div ng-controller="xxx">
<div yyy>
<button ng-click="sayHi()">Hi</button>
<div>
</div>
when you click the "Hi" button, the alert dialog will pop up with the message "Hello World" not "Error: Scope".
app
.controller('xxx', function($scope) {
$scope.sayHi = function(){alert('Error: Scope');};
})
.directive('yyy', function() {
return {
scope: {},
link: function(scope,elem,attrs) {
scope.sayHi = function(){alert('Hello World');};
}
};
});
Moreover, I tried this:
app
.controller('xxx', function($scope) {
$scope.sayHi = function(){alert('Error: Scope');};
})
.directive('yyy', function() {
return {
scope: {},
controller: function($scope, $compile) {$scope._compile = $compile;}
link: function(scope,elem,attrs) {
elem.children().forEach(function(one) {
scope._compile(one)(scope);
});
scope.sayHi = function(){alert('Hello World');};
}
};
});
Then it will pop up two alert dialogs with the message "Error: Scope" and "Hello World" respectively.
Now I found the solution - load template dynamically and use $compile to specify scope:
.controller('main', function($scope) {
$scope.sayHi = function() {alert('scope error');};}
)
.directive('scopeInherit', ['$http', '$compile', function($http, $compile) {
return {
scope: {},
link: function(scope, elem, attrs) {
scope.sayHi = function() {alert('hello world');};
scope.contents = angular.element('<div>');
$http.get(elem.attr('contentsURL'))
.success(function (contents) {
scope.contents.html(contents);
$compile(scope.contents)(scope);
});
},
};
}]);
Then we write HTML:
<div ng-controller="main">
<div scope-inherit contents="test.html"></div>
</div>
where there is a test.html:
<button ng-click="sayHi()">speak</button>
Then click on the "speak" button, it will pop up the alert dialog with "hello world"
To do what you want, you need to use a template (either as a string or a templateUrl). If angularjs would work how you expect it in this case then a lot of the angular directives wouldn't work right (such as ng-show, ng-click, etc).
So to work how you want it, change your html to this:
<script type="text/ng-template" id="zzz.html">
<button ng-click="sayHi()">Hi 2</button>
</script>
<div ng-controller="xxx">
<button ng-click="sayHi()">Hi 1</button>
<div yyy></div>
</div>
And update your directive definition to use a templateUrl (or you can provide the string as a template property)
app
.controller('xxx', function($scope) {
$scope.sayHi = function() {
console.error('Error: Scope in xxx', new Date());
};
})
.directive('yyy', function() {
return {
scope: {},
templateUrl: 'zzz.html',
link: function(scope, elem, attrs) {
scope.sayHi = function() {
console.log('Hello World in zzz', new Date());
};
}
};
});
Here's a plunker with this code: http://plnkr.co/edit/nDathkanbULyHHzuI2Rf?p=preview
Update to use multiple templates
Your latest comment was a question about what if you wanted to use different templates on the same page. In that case we can use ng-include.
html:
<div yyy contents="template1.html"></div>
<div yyy contents="template2.html"></div>
<div yyy contents="template3.html"></div>
js:
app
.controller('xxx', ...)
.directive('yyy', function() {
return {
scope: {
theTemplateUrl: '#contents'
},
template: '<ng-include src="theTemplateUrl"></ng-include>',
link: function(scope, elem, attrs) {
scope.sayHi = function() {
console.log('Hello World in yyy', new Date());
};
}
};
});
The benefit of using ng-include is that this is already built into angularjs and is well tested. Plus it supports loading template either inline in a script tag or from an actual url or even pre-loaded into the angular module cache.
And again, here is a plunker with a working sample: http://plnkr.co/edit/uaC4Vcs3IgirChSOrfSL?p=preview