Angular Directive isn't running and templateUrl isn't showing - javascript

Can't find why this directive isn't runnning.
No errors of any type, link function not being called and template is not being rendered.
Original code is on TypeScript but I have reproduced exactly the same behavior in a plnkr trying to make the problem come up, but still.
Plnkr version: http://plnkr.co/edit/vBARsB9PhZ4txjlmolMM?p=preview
JS
angular.module('DirectivesApp', [])
.controller('MainCtrl', ['$scope', function($scope) {
$scope.text = 'find this, also this';
$scope.Items = [{
Key: 'find this',
Value: 'FOUND 1'
}, {
Key: 'also this',
Value: 'FOUND 2'
}];
}]).directive('multiSelect', function() {
return {
templateUrl: 'multipleSelect-template.html',
$scope: {
text: '#text',
Items: '&Items'
},
restrict: 'A',
link: function($scope, element, attrs) {
$scope.text = attrs.text;
}
};
});
HTML
<div ng-app="DirectivesApp">
<div ng-controller="MainCtrl">
<multi-select text="{{text}}" Items="{{Items}}"></multi-select>
</div>
</div>
Template
<input type="text" disabled value="{{text}}" />
<input type="checkbox" ng-repeat="item in Items" value="{{item.Key}}"/><label>{{item.Value}}</label>
PS: trying to make a custom multiselect control.

To summarise all the comments above, this should be all you need
return {
templateUrl: 'multipleSelect-template.html',
scope: {
text: '#',
Items: '='
}
};
The default restrict is "EA" anyway and you don't need to bind attrs.text to the $scope as it's already bound in the isolate scope.

Related

How to pass and update data through custom directive with ng-bind-html

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>

How to pass a value into a directives controller in angular?

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);
}
};
});

Disable item in angularjs directive with expression from parent controller

I have a list of items which are a custom directive and each of those items has a remove button. Now I want to disable this remove button when there is only one item left in my list, but for some reason it doesn't work as expected.
I've made a plunker example where you an watch this behavior.
I guess there is something wrong with the canRemove: '&' part of my directive. But I don't know how to get it working.
View:
<body ng-controller="MainCtrl as vm">
<div ng-repeat="item in vm.items">
<my-directive item="item"
canRemove="vm.items.length != 1"
remove="vm.remove(item)">
</my-directive>
</div>
</body>
Controller:
app.controller('MainCtrl', function($scope) {
var vm = this;
vm.items = [
{
number: 1
} , {
number: 2
}
];
vm.remove = function(item) {
vm.items.splice(vm.items.indexOf(item), 1);
}
});
Directive:
app.directive('myDirective', function() {
return {
restrict: 'EA',
scope: {
item: '=',
canRemove: '&',
remove: '&'
},
controller: function() {
var vm = this;
vm.onRemove = function() {
vm.remove({ item: vm.item });
};
},
controllerAs: 'vm',
bindToController: true,
template: '<button ng-disabled="!vm.canRemove" ng-click="vm.onRemove()">' +
' Remove {{ vm.item.number }}' +
'</button>'
}
});
PS: Since I'm pretty new to angular is the way I'm handling the removing of the items a good practice? Or should I use broadcast and on instead?
First of all attribute should look like can-remove:
<my-directive item="item" can-remove="vm.items.length > 1" remove="vm.remove(item)"></my-directive>
Then in scope configuration you need to use = binding instead of &:
scope: {
item: '=',
canRemove: '=',
remove: '&'
},
Demo: http://plnkr.co/edit/DlZafON6HEdoyhzvwNIh?p=preview

ng-click, scopes and nested directives in AngularJS

I have these nested directives the very inner of which has an 'X' sign, which is, when clicked, is supposed to delete an item (classic problem). Basically, the whole thing is a menu.
I have added an ng-click to the 'X' sign/button of the item, but i am very confused on how to link this whole thing back to the controller, so that i can call a deleteItem() function and actually remove the item. I also want to have scope for the sidebar-item separated (the original version of this code is slightly more elaborated and has conditional statements)
Here's what i have so far
The full working - i.e. not really working - version can be found in this jsfiddle
Here's the relevant part of HTML:
<div ng-app="demoApp">
<div ng-controller="sidebarController">
<div sidebar>
<div sidebar-item ng-repeat="item in items" item="item"></div>
</div>
<button ng-click="addItem();">Add Item</button>
</div>
</div>
And here's the JavaScript:
var demoApp = angular.module('demoApp', []);
demoApp.controller("sidebarController", ["$scope", function($scope) {
$scope.items = [
];
$scope.itemId = 1;
$scope.addItem = function() {
var inx = $scope.itemId++;
$scope.items.push( { id: inx, title: "Item " + inx, subTitle: "Extra content " + inx } );
};
$scope.deleteItem = function(item) {
console.log("Delete this!");
console.log(item);
};
}]);
demoApp.directive("sidebar", function() {
return {
restrict: "A",
transclude: true,
template: '<div><div ng-transclude></div></div>',
controller: ["$scope", function($scope) {
this.deleteItem = function(item) {
$scope.deleteItem(item);
$scope.$apply();
};
}]
};
});
demoApp.directive("sidebarItem", function() {
return {
restrict: "A",
scope: {
item: "="
},
require: "^sidebar",
template: '<div><span>{{ item.title }}</span><br /><span>{{ item.subTitle }}</span><br /><span ng-click="deleteItem(item)">X</span></div>',
};
});
Im sure the answer is simple, but I just cant find it.
If you want to use a required controller function you need to inject it into the link function
in sidebar-item add
link : function (scope, element, attrs, sidebar) {
scope.deleteItem = function (item) {
sidebar.deleteItem(item);
}
}

Is a $compile needed or is my directive wrongly structured?

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 )

Categories