Reading the documentation I'm not sure if I should be doing a pre-compile of this directive or if my methodology doesn't work. The error i get is an "unexpected token email in emails".
Is it possible that the directive's internal controller hasnt passed the email class to the scope of the directive?
//html
<div data-ng-app = "appSubs">
<email-subscription>
</email-subscription>
</div >
//js
angular.module('appSubs', [])
.directive('emailSubscription', function () {
return {
restrict: 'E',
template: '<ul><li ng-repeat="{{email in emails}}">Name: {{email.name}} </li>' +
'</ul>',
controller: function ($scope, $element) {
$scope.emails = [{
name: 'Weekly Newsletter'},{
name: 'Monthly Newsletter'}
];
}
};
});
just remove {{ and }} from email in emails )
Related
i created a plug-in for field
angular.module('ersProfileForm').directive('ersProfileEditableField', ['$templateCache', '$compile', 'profileFieldService', 'RolesService',
function($templateCache, $compile, profileFieldService , RolesService){
return {
restrict: 'AE',
templateUrl: '',
scope: {
ersProfileEditableField: '=',
ersProfileSectionData: '=',
ersProfileEditableFieldValue: '=',
ersBulkEdit: '<'
},
controller: ['$scope', '$http','$q','$resource', function($scope, $http, $q, $resource){
$http.get('rest/roles',{}).then(function(response){
$scope.roles = response.data;
});
}],
link: function(scope, iElement, iAttrs, controller){
iElement.append(jQuery(profileFieldService.getTemplate(scope.ersProfileEditableField.type, scope)));
$compile(iElement.contents())(scope);
}
};
}]);
roles data will be used in this template
angular.module('ersProfileForm').factory('profileFieldService', ['$resource', function($resource){
var factory = {};
factory.getTemplate = function(type, scope){
scope.field = scope.ersProfileEditableField;
var tpl = '<div ng-repeat ="role in roles"'>
+' <label>{{role.name</label>'
+' </div>'
break;
return tpl;
};
return factory;
}]);
i want roles array in this template but service is taking time so roles is not defined in template it is executing after some time
my question is that i want roles data from the request only then go to template which is defined in link?
Try var tpl = '<div ng-repeat ="role in roles" ng-show="roles&&(roles.length>0)"> '+' <label>role.name</label>' +' </div>'
Did you tried using the $q promise object ? resolve it in your $http method, then use it with .then :)
Here is a link from the docs :
https://docs.angularjs.org/api/ng/service/$q
The template needs double curly brackets {{ }} to bind data to the DOM:
factory.getTemplate = function(type, scope){
scope.field = scope.ersProfileEditableField;
var tpl = '<div ng-repeat ="role in roles"'>
// +' <label>role.name</label>'
// USE {{ }} for interpolation
+' <label>{{role.name}}</label>'
+' </div>'
return tpl;
};
The compile can be delayed by using a watcher:
link: function(scope, iElement, iAttrs, controller){
scope.$watch("::roles", function (newValue) {
if (newValue) {
iElement.append(
profileFieldService
.getTemplate(scope.ersProfileEditableField.type, scope)
);
$compile(iElement.contents())(scope);
};
});
}
The watcher waits for the roles data that is fetched from the server before doing the compile. It uses a one-time binding so that the compile is performed only once but the ng-repeat directive will continue to update the DOM as the value of roles changes.
Controller:
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.temp = {
'name': 'Test'
};
}]);
Template:
<custom-field ng-model="temp.name">
<md-input-container class="addon-menu">
<label>Name</label>
<input ng-model="ngModel" type="text" ng-focus="setLastFocusedElement($event)" />
</md-input-container>
</custom-field>
Directive:
app.directive('customField', function($timeout) {
return {
restrict: 'E',
scope: {
ngModel: '='
},
link: function($scope, $element, $attrs) {
console.log($scope.ngModel); // prints "test"
}
};
});
The problem is that once template is rendered, I can't see the value attached to input - it's empty, but I'm expecting to works, because inside link function it's printed correctly.
You are trying to access the directive scope in your template as the controller's scope. Move the markup inside the directive's template instead.
Directive:
app.directive('customField', function($timeout) {
return {
restrict: 'E',
scope: {
ngModel: '='
},
link: function($scope, $element, $attrs) {
console.log($scope.ngModel); // prints "test"
},
template: '<md-input-container class="addon-menu"><label>Name</label><input ng-model="ngModel" type="text" ng-focus="setLastFocusedElement($event)" /></md-input-container>'
};
Template:
<custom-field ng-model="temp.name"></custom-field>
You can also use separate html files as directive templates, which is good practise.
Are you trying to see the value in controller?
Please try $parent.$scope to see if value exist.
I would like to add a common custom directive where when instantiated, will look through string input and returns string with proper telephone HTML a tag. Currently the logic is within message directive, where in the html I have:
<div ng-repeat="message in messages >
<p ng-bind-html=message.title</p>
</div>
and in directive I have:
.directive('message', function () {
return {
scope: {
messages: "=messages",
},
restrict: 'E',
controller: 'MessageSummary',
controllerAs: 'messageSummary'
};
})
.controller('MessageSummary', ['$scope', function ($scope) {
angular.forEach($scope.messages, function (message, index) {
$scope.messages[index].title = wrapStringWithPhoneNumberHTMLTag($scope.messages[index].title);
});
I need to extract this logic out to its own directive so it can be reused anywhere. Currently I added:
<div ng-repeat="message in messages >
<p ng-bind-html=message.title ng-phone-caller=message.title</p>
</div>
and
.directive('ngPhoneCaller',function() {
return {
scope: {
inputString: '='
},
link: function (scope) {
scope.inputString = wrapStringWithPhoneNumberHTMLTag(scope.inputString);
}
}
but it scope.inputString that is passed into the function is undefined. Also, I'm a bit lost on how I would integrate this with ng-bind-html-> I need this to validate the returned HTML string after its been passed into the custom common directive. Also, is this the best way of doing it? It seems like anywhere someone uses my attribute custom directive they would need to implement ng-bind-html, is there a way to integrate inject HTML safely within the custom directive?
Basic example to use directive by passing data into the template layout
var app = angular.module('myApp', []);
app.controller('MyController1', function ($scope) {
$scope.data = [
{
'title': 'one'
},
{
'title': 'two'
},
{
'title': 'three'
}
];
});
app.controller('MyController2', function ($scope) {
$scope.data = [
{
'title': 'satu'
},
{
'title': 'dua'
},
{
'title': 'tiga'
}
];
});
app.directive('myDirective', function () {
'use strict';
return {
restrict: 'E',
scope: {
data: '=data'
},
template: [
'<div ng-repeat="record in data">',
'{{ record.title }}',
'</div>'
].join('')
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController1">
<my-directive data="data">
</div>
<br \>
<div ng-controller="MyController2">
<my-directive data="data">
</div>
</div>
My directive has a controller and I am trying to figure out how to pass a value from the directive that was passed in. In the example below 'name' is not valid posted to the console but it shows in the html when rendered. Obviously my example is an over simplication, but you get the point.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log(name);
}
};
});
<helpLabel name="test"></helpLabel>
The answer I found is to use bindToController along with controllerAs now effective angular 1.4.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope:{},
bindToConroller: {
name: '#',
},
template: '<span>{{cntrl.name}}</span>',
controller: function () {
console.log(cntrl.name);
},
controllerAs: "cntrl"
};
});
http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html
This is because when it is being rendered to the html, you encapsulated name within {{}}. If you wan't to access the name property within your directive you have to change your code.
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log($scope.name);
}
};
});
In your code, console.log(name);, the variable name is not known your directive and hence not able to access it, but since angular has done binding to 'name' variable, it can render {{name}}.
You should access variable name as $scope.name as variable name is present inside current scope.
Modify your code as follow:
angular.module('myApp')
.directive('helpLabel', function() {
return {
restrict: 'E',
scope: {
name: '#',
},
template: '<span>{{name}}</span>',
controller: function ($scope) {
console.log($scope.name);
}
};
});
I want to create a directive that has dynamic view with dynamic controller. the controller and the template view is coming from the server.
The Directive
var DirectivesModule = angular.module('BPM.Directives', []);
(function () {
'use strict';
angular
.module('BPM.Directives')
.directive('bpmCompletedTask', bpmCompletedTask);
bpmCompletedTask.$inject = ['$window'];
function bpmCompletedTask ($window) {
// Usage:
// <bpmCompletedTask></bpmCompletedTask>
// Creates:
//
var directive = {
link: link,
restrict: 'E',
scope: {
type: '=',
taskdata: '=',
controllername:'#'
},
template: '<div ng-include="getContentUrl()"></div>',
controller: '#',
name: 'controllername'
};
return directive;
function link(scope, element, attrs) {
scope.getContentUrl = function () {
return '/app/views/TasksViews/' + scope.type + '.html';
}
scope.getControllerName = function ()
{
console.warn("Controller Name is " + scope.type);
return scope.type;
}
}
}
})();
Here how I'm trying to use the directive
<div ng-controller="WorkflowHistoryController as vm">
<h2>Workflow History</h2>
<h3>{{Id}}</h3>
<div ng-repeat="workflowStep in CompletedWorkflowSteps">
<bpm-completed-task controllername="workflowStep.WorkflowTaskType.DataMessageViewViewName" taskdata="workflowStep.WorkflowTaskOutcome.TaskOutcome" type="workflowStep.WorkflowTaskType.DataMessageViewViewName">
</bpm-completed-task>
</div>
</div>
The problem now is when the directive gets the controller name it get it as literal string not as a parameter.
Is it doable ?
if it's not doable, What is the best solution to create dynamic views with its controllers and display them dynamically inside ng-repeat?
Thanks,
Update 20 Jan I just updated my code in case if some one interested in it. All the Credit goes to #Meligy.
The First Directive:
(function () {
'use strict';
angular
.module('BPM.Directives')
.directive('bpmCompletedTask', bpmCompletedTask);
bpmCompletedTask.$inject = ['$compile', '$parse'];
function bpmCompletedTask ($compile, $parse) {
var directive = {
link: function (scope, elem, attrs) {
console.warn('in the first directive - before if');
if (!elem.attr('bpm-completed-task-inner'))
{
console.warn('in the first directive');
var name = $parse(elem.attr('controllername'))(scope);
console.warn('Controller Name : ' + name);
elem = elem.removeAttr('bpm-completed-task');
elem.attr('controllernameinner', name);
elem.attr('bpm-completed-task-inner', '');
$compile(elem)(scope);
}
},
restrict: 'A',
};
return directive;
}
})();
The Second Directive
angular
.module('BPM.Directives')
.directive('bpmCompletedTaskInner',['$compile', '$parse',
function ($window, $compile, $parse) {
console.warn('in the second directive');
return {
link: function (scope, elem, attrs) {
console.warn('in the second directive');
scope.getContentUrl = function () {
return '/app/views/TasksViews/' + scope.type + '.html';
}
},
restrict: 'A',
scope: {
type: '=',
taskdata: '=',
controllernameinner: '#'
},
template: '<div ng-include="getContentUrl()"></div>',
controller: '#',
name: 'controllernameinner'
};
}]);
The Html
<div ng-repeat="workflowStep in CompletedWorkflowSteps">
<div bpm-completed-task controllername="workflowStep.WorkflowTaskType.DataMessageViewViewName" taskdata="workflowStep.WorkflowTaskOutcome.TaskOutcome"
type="workflowStep.WorkflowTaskType.DataMessageViewViewName">
</div>
</div>
Update:
I got it working, but it's really ugly. Check:
http://jsfiddle.net/p6Hb4/13/
Your example has a lot of moving pieces, so this one is simple, but does what you want.
Basically you need a wrapper directive that takes the JS object and converts into a string property, then you can use هى your directive for everything else (template, scope, etc).
.
Update 2:
Code Inline:
var app = angular.module('myApp', []).
directive('communicatorInner', ["$parse", "$compile",
function($parse, $compile) {
return {
restrict: 'A',
template: "<input type='text' ng-model='message'/><input type='button' value='Send Message' ng-click='sendMsg()'><br/>",
scope: {
message: '='
},
controller: '#'
};
}
]).
directive('communicator', ['$compile', '$parse',
function($compile, $parse) {
return {
restrict: 'E',
link: function(scope, elem) {
if (!elem.attr('communicator-inner')) {
var name = $parse(elem.attr('controller-name'))(scope);
elem = elem.removeAttr('controller-name')
elem.attr('communicator-inner', name);
$compile(elem)(scope);
}
}
};
}
]).
controller("PhoneCtrl", function($scope) {
$scope.sendMsg = function() {
alert($scope.message + " : sending message via Phone Ctrl");
}
}).
controller("LandlineCtrl", function($scope) {
$scope.sendMsg = function() {
alert($scope.message + " : sending message via Land Line Ctrl ");
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
<div ng-app="myApp">
<div ng-init="test = {p: 'PhoneCtrl', l: 'LandlineCtrl' }">
<communicator controller-name="test.p" message="'test1'"></communicator>
<communicator controller-name="test.l"></communicator>
</div>
</div>
.
Original (irrelevant now but can help other related issues)
Yes, it should work.
A test with Angular 1.3:
http://jsfiddle.net/p6Hb4/9/
Things to check:
Is the controller defined and added to the module? It will not work
If the controller is just a global function it won't work. It has to be added via the <myModule>.controller("<controllerName>", <functiion>) API
Does ng-controller work? Just adding it to the template
Similarly, does using ng-controller directly outside of the directive work?