AngularJS: include not working from a custom directive - angularjs

I have a custom directive and I would like to use it to include an html content to the document after clicking on it.
Plunker: http://plnkr.co/edit/u2KUKU3WgVf637PGA9A1?p=preview
JS:
angular.module("app", [])
.controller("MyController", function ($scope) {
})
.directive('addFooter', ['$compile', '$rootScope', function($compile, $rootScope){
return {
restrict: 'E',
template: '<button>add footer</button>',
controller: 'MyController',
link: function( scope, element, attrs, controller) {
element.bind( "click", function() {
scope.footer = "'footer.html'";
})}
};
}])
HTML:
<body ng-app="app">
<script type="text/ng-template" id="footer.html">
FOOTER
</script>
<div ng-controller="MyController">
<add-footer></add-footer>
<div ng-include="footer"></div>
</div>
</body>
Not sure why it is not working, as it worked fine before it was moved into the directive. Outside the directive, I was also referencing to $scope.footer with some link. I tried using $rootScope, but also no effect. Any tips please?

First. Remove unnecessary quote symbols:
element.bind( "click", function() {
scope.footer = "footer.html"; // not "'footer.html'"
});
Second. You should notify angularjs that you have asynchronously updated scope values:
element.bind("click", function() {
scope.$apply(function() {
scope.footer = "footer.html";
});
});
Or like that
element.bind("click", function() {
scope.footer = "footer.html";
scope.$apply();
});

Related

How can I replace link hrefs with ngClicks in dynamically generated HTML within AngularJS?

I'm consuming dynamically generated HTML from an API which may contain hyperlinks, and I'm wanting to replace the hrefs within them with ngClicks. The following directive appears to modify the HTML as intended when I check it in a DOM inspector, but clicking it does nothing. What am I doing wrong?
app.directive('replaceLinks', ['$compile', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(function(scope) {
return scope.$eval(attrs.replaceLinks);
}, function(value) {
element.html(value);
angular.forEach(element.contents().find("a"), function(link) {
link.removeAttribute("href");
link.removeAttribute("target");
link.setAttribute("ng-click", "alert('test')");
});
$compile(element.contents())(scope);
});
}
};
}]);
Instead of removing the href please set it to blank (this will preserve the link css), also the ng-click calling the alert can be done by calling the alert('test') inside of a scope method, why the alert didn't fire, is explained in this SO Answer, please refer the below sample code!
// <body ng-app='myApp' binds to the app being created below.
var app = angular.module('myApp', []);
app.directive('replaceLinks', ['$compile', function($compile) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
angular.forEach(element.find("a"), function(link) {
link.setAttribute("href", "");
link.removeAttribute("target");
link.setAttribute("ng-click", "scopeAlert('test')");
});
$compile(element.contents())(scope);
}
};
}]);
// Register MyController object to this app
app.controller('MyController', ['$scope', MyController]);
// We define a simple controller constructor.
function MyController($scope) {
// On controller load, assign 'World' to the "name" model
// in <input type="text" ng-model="name"></input>
$scope.name = 'World';
$scope.scopeAlert = function(name) {
window.alert(name);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller='MyController' ng-app="myApp">
<div replace-links>
test 1
test 2
test 3
</div>
</div>

Angular complains about unknown provider with this simple directive?

I am adding this my-resize directive:
<body ng-controller="MainCtrl" my-resize="resize">
<p>width:{{width}} height:{{height}}</p>
</body>
,where resize is a function defined in the MainCtrl controller (see: http://plnkr.co/edit/Z8ckbLbRcA6P6XqzU1fx)
The directive is very simple:
app.directive('myResize', function($scope){
return{
restrict: 'A',
scope: {
ngResize: '&'
},
link: function($scope, $elem, $attr){
$scope.$on('resize', ngResize);
}
};
});
Yet I am getting Error: $injector:unpr Unknown Provider and I have no idea why.
var app = angular.module('app', []);
app.directive('myResize', ['$window', function($window) {
return {
link: function(scope, elem, attrs) {
scope.onResize = function() {
scope.height = $window.innerHeight;
scope.width = $window.innerWidth;
}
scope.onResize();
angular.element($window).bind('resize', function() {
scope.onResize();
scope.$apply();
})
}
}
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div my-resize>
window height: {{height}}
window width:{{width}}<br />
</div>
</div>
$scope can not be injected to directive. You have change the code to inject $scope in controller of directive.
$scope is not a service($scopeProvider is not exist in angular js) it is something special that is injected by angular itself into the controller as a child of $rootScope.
so you cannot explicitly inject it in service,directive...etc.
you can inject it explicitly in the controller of direcitve (not directly to the directive).
http://plnkr.co/edit/mxEMXxIKOrJtRqQa4IQb?p=preview

Angular 1.X - Accessing controller variable through directive using $watch

Within a controller I have an ajax call that populates $scope.main_data. I want to within a directive get that data when it populates. However the two issues I'm having is:
I cannot seem to access $scope.main_data from the directive.
$scope.watch doesn't seem to work because of this.
How can I print the data from the directive once the data arrives?
CONTROLLER:
app.controller('myCtrl', ['$scope','$http', function($scope, $http) {
$scope.main_data = [];
$http.get("some_url").success( function(data) {
$scope.main_data = data;
});
}]);
DIRECTIVE:
app.directive('myDir', function($compile, $rootScope) {
return {
restrict: 'A',
scope: {
items: '=items'
},
link: function($scope, element, attrs, ctrl) {
$scope.$watch($scope.main_data ,function(newValue,oldValue){
if (newValue){
console.log($scope.main_data);
}
});
}
};
});
HTML:
<div ng-controller="myCtrl">
<div my-dir>
<div>
</div>
The directive in the html exists within the controller but for some reason I can't access the controller scope through $scope but $scope.$parent.
You've almost got it.
app.directive('myDir', function($compile, $rootScope) {
return {
restrict: 'A',
scope: {
items: '=items'
},
link: function($scope, element, attrs, ctrl) {
$scope.$watch("items",function(newValue,oldValue){
if (newValue){
console.log($scope.main_data);
}
});
}
};
});
And html:
<div ng-controller="myCtrl">
<div my-dir items="main_data">
</div>
</div>
Even though you can "hack" around and access main_data using series of$parent calls on your scope and using some other methods, just pass it in to your directive with = binding, so it will be updated when controller scope is updated. In fact you don't even need $watch in this case, you will always have actual data.

Get transcluded text in directives controller

I can get some text from my directive into my directives controller like this:
The html:
<my-directive text="Some text"></my-directive>
In the directive, I can get hold of the text like this:
bindToController: {
text: "#"
};
And I could use it like this in the directive's controller:
controller: function() {
this.textUpperCase = this.text.toUpperCase();
}
But how could can I get hold of the text in the directives controller via transclusion? So that I can have the html like this:
<my-directive>Some text</my-directive>
As mentioned in the comments you could use element.html() or transclusion.
But I would prefer transclusion because that's easier to work with the data. You can use $transclude in your controller or transcludeFn in compile or link method.
Here I think the best would be the controller.
Please have a look at this fiddle or the demo below.
I think injecting the $element into controller won't work becasue you would get the uncompiled template with-out the data you're looking for.
angular.module('demoApp', [])
.controller('mainCtrl', function($scope) {
$scope.hello = 'hello world from scope';
})
.directive('upperCase', function() {
return {
restrict: 'E',
transclude: true,
scope: {
},
template: '<div>{{text}}</div>',
controller: function($scope, $transclude, $element) {
$transclude(function(clone, scope) {
//console.log(clone.text(), scope.hello);
console.log(clone);
$scope.text = clone.text().toUpperCase();
//transcludedContent = clone;
//transclusionScope = scope;
});
//console.log($element.html()); // not working will get the uncompiled template from directive
console.log($scope.text); // can be used here too
},
link: function(scope, element, attrs, ctrl, transclude) {
var text = element.html();
//console.log(transclude);
//element.html(text.toUpperCase()); // also working (add ng-transclude to your template)
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainCtrl">
<upper-case>hello world</upper-case>
<upper-case>hello angular</upper-case>
</div>

AngularJS. Multiple select JQuery plugin

What is proper way to implement this bootstrap select plugin (http://silviomoreto.github.io/bootstrap-select/) to angular. I have put it in the directive:
App.directive('selectmultiple', [function(){
return function(scope, element, attributes){
element = $(element[0]);
element.selectpicker({
})
}
})
But it's not working. If I write in Chrome console $('.selectpicker').selectpicker({}) - proper combobox appear (opened), but a can't close it.
Thanks
I created a working example in jsfiddle. The way I found to use bootstrap-select plugin with angular was:
HTML:
<div ng-app="myApp">
<div ng-controller="MyCntrl">
<select ng-model='color' multiple ng-multiple="true" ng-options='c.name for c in colors' select-multiple></select>
</div>
</div>
Controller:
angular.module('myApp.controllers', [])
.controller('MyCntrl', ['$scope', function($scope) {
$scope.colors = [
{name:'black'},
{name:'white'},
{name:'red'},
{name:'blue'},
{name:'yellow'}
];
$scope.color = $scope.colors[2]; // red
}]);
Directive:
angular.module('myApp.directives', [])
.directive('selectMultiple', function() {
return function(scope, element, attributes){
element.selectpicker({});
scope.$watch(function () {
return element[0].length;
}, function () {
element.selectpicker('rebuild');
});
// Watch for any changes from outside the directive and refresh
scope.$watch(attributes.ngModel, function () {
element.selectpicker('refresh');
});
}
});
I hope it helps you ;)

Resources