Talking to Angular Directive from Controller - angularjs

I have a directive and I want to call a method of the Directive from outside controller . That means when I click a button in the main controller , I want to hide a component in the directive . Is this really possible ,If yes please help me .
Kamal

To call directive methods outside in a controller I would share a directive control object with the controller. Inside the controller you can call methods of this control object and they get executed inside your directive.
create a control object inside your directive
share this control object with the controller using tw data binding
call methods on this control object inside your controller
here is a plunker that demonstrates it: http://plnkr.co/edit/MqN9yS8R5dnqTfjqldwX?p=preview

You can accomplish this by allowing your directive to listen to a scoped property from your controller. Using isolated scope and the =, you can tell your directive what to pay attention to in order to hide its component:
Html:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angular.js#*" data-semver="1.2.0-rc3-nonmin" src="http://code.angularjs.org/1.2.0-rc.3/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="Ctrl">
<h1>Hello Plunker!</h1>
<button ng-click="action()">Toggle</button>
<the-directive show-component="showIt"></the-directive>
</body>
</html>
JavaScript:
var myApp = angular.module('myApp', []);
myApp.controller('Ctrl', function($scope) {
$scope.showIt = true;
$scope.action = function() {
$scope.showIt = !$scope.showIt;
}
});
myApp.directive('theDirective', function() {
return {
restrict: 'E',
scope: {
'showComponent': '='
},
template: '<div><div ng-show="showComponent">show Me!</div></div>'
}
})
Here is a plunker demonstrating the technique.

Related

AngularJS Directive Template is not display

I start learning AngularJS today with directive ... I can't get directive work. Please help
<html ng-app="ngBasic">
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script>
var app = angular.module('ngBasic', []);
app.controller('ngBasicCtrl', function($scope) {
$scope.age = 20;
});
app.directive('myDirective', function($scope) {
return {
template: '<h1>{{age}}</h1>'
}
});
</script>
</head>
<body ng-controller="ngBasicCtrl">
<h1>{{age}}</h1>
<my-directive></my-directive>
<div my-directive></div>
<div class='my-directive'></div>
</body>
</html>
https://jsfiddle.net/bigzidane/t8Lv3mpg/2/
Currently, the page onlys show 20. Expecting tag but not displaying yet.
Use the scope option to create an isolated scope the template can refer to :
app.directive('myDirective', function() {
return {
scope: {
age: '='
},
template: '<h1>{{age}}</h1>'
}
});
Now you can pass the controller $scope's age to the directive scope, for example this way :
<my-directive age="age+1"></my-directive>
Will render out 21. Updated fiddle -> https://jsfiddle.net/t8Lv3mpg/3/
You have to remove the $scope from the function returning your directive as it does not take a $scope parameter.
app.directive('myDirective', function() {
return {
template: '<h1>{{age}}</h1>'
}
});

angularjs - access transclude html scope from hosting directive

I have a simple directive with transcluded html.
I want to be able to inject directive scope params to the transclude.
I wrote a simple example in plunker :
https://plnkr.co/edit/jqyiQdgQxbeTrzyidZYF?p=preview
I know in angular 4 it can be done, but I can't find a good way to do it in angularjs.
// Code goes here
var app = angular.module("app", []);
app.controller("mainCtrl", function($scope) {
$scope.users = ["tal", "oren", "orel", "shluki"];
$scope.deleteUser = (user) => {alert("trying to delete", user);}
});
app.directive('myList', function myList() {
return {
restrict: 'E',
transclude: true,
template: "<div><table><tr ng-repeat='item in collection'><td> This is inside myList - user name: {{item}} <ng-transclude></ng-transclude></td></tr></table></div>",
scope: {
collection: "="
},
replace: true
};
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angularjs#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="mainCtrl">
<h1>Hello Plunker!</h1>
<my-list collection="users">
<h2>This is transclude</h2>
<button ng-click="deleteUser(user)">Delete user: {{user ? user : "User name should be here"}}</button>
</my-list>
</body>
</html>
Will really appreicate some help.
plunker: https://plnkr.co/edit/jqyiQdgQxbeTrzyidZYF?p=preview
Here's a working plunker with your example.
http://plnkr.co/edit/BjSowyQdLXd0xoCZFqZ6?p=preview
The idea is to pass it as contents and not html as string. $compile is here because the link is done after ng-repeats already has transcluded its own template.
var template = '<h1>I am foo</h1>\
<div ng-repeat="item in users">\
<placeholder></placeholder>\
<hr>\
</div>';
var templateEl = angular.element(template);
transclude(scope, function(clonedContent) {
templateEl.find("placeholder").replaceWith(clonedContent);
$compile(templateEl)(scope, function(clonedTemplate) {
element.append(clonedTemplate);
});
});
If you want a proper explanation of what the problem was you should check the detailed answer here : Pass data to transcluded element
Hope this helped you out

Does controllerAs work with Isolated Scope?

I'm familiar with using controllerAs, but do not understand why, when using with isolated scope, none of my controller properties are showing up on the scope.
Here's a plunker showing what I'm talking about.
Why is vm.min and vm.max both blank when I specifically set properties from within the controller function?
If I remove the isolate scope, {{vm.min}} works, as expected. But with the isolated scope, it does not.
1) this.min was set within the controller, so {{vm.min}} should have a value, right?
2) the property max was set on the element, so when i use bindToController and the isolated scope, {{max}} should have a value, right?
Since you have taken the vm.min and vm.max inside the my-example directive, it did not work for you.
Check this code once,
var myApp = angular.module('myApp', []);
function myExample() {
var directive = {
restrict: 'EA',
scope: {
max: '='
},
controller: ExampleController,
controllerAs: 'vm',
bindToController: true, // because the scope is isolated,
templateUrl: `tpl.html`
};
return directive;
}
ExampleController.$inject = ['$scope'];
function ExampleController($scope) {
// Injecting $scope just for comparison
var vm = this;
vm.min = 3;
}
angular
.module('myApp')
.directive('myExample', myExample);
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#*" data-semver="1.5.8" src="https://code.angularjs.org/1.5.8/angular.js"></script>
</head>
<body>
<h1>Why are vm.min and vm.max both blank?</h1>
<my-example max="5">
</my-example>
<script src="script.js"></script>
<script type="text/ng-template" id="tpl.html">
<div>
vm.min: {{vm.min}}
<br/>
vm.max: {{vm.max}}
</div>
</script>
</body>
</html>
If you want to use the templates inside the directive, you should use transclude option.
You need a template or templateUrl attribute in which those values need to be rendered.

How do I include HTML from an attribute as a token in a directive template

I want to inject HTML as an attribute into a template and have it display within the directive that passed the attribute.
My HTML
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#*" data-semver="1.4.0-rc.0" src="https://code.angularjs.org/1.4.0-rc.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app">
<div>
<my-test mymessage='<b>Booya!</b>'></my-test>
</div>
</body>
</html>
My Javascript
app = angular.module('app', [])
.directive("myTest", function(){
return {
scope: {
mymessage: '='
},
restrict: 'E',
transclude: true,
template: '<p>Guess what...{{mymessage}}...you know it!</p>'
};
});
Here is the code in Plunker: http://plnkr.co/edit/ZJSkf1Ye4ccKURTJU8KD?p=preview
Note how it shows the literal for the binding.
I'm sure there are several problems here:
I am probably not properly binding the attribute within the directive scope
Once I have problem #1 solved I am pretty sure the HTML will be escaped.
What changes do I need to make in order to get the directive to render properly?
If you are binding HTML without Angular code (expressions and directives), then you need to use ng-bind-html:
scope: {
mymessage: "#" // no need for two-way binding
},
template: '<p>Guess what...<span ng-bind-html="mymessage"></span>...you know it!</p>'
This, on its own, would not work since it is unsafe. You have two options then:
1) include ngSanitize dependecy to your app:
angular.module("app", ["ngSanitize"])
This will automatically apply HTML sanitation - Demo
or, 2) use $sce service and call $sce.trustAsHtml on the variable holding the HTML content. This would not work, however with one-way string binding "#".

Angular ui.router, call parent controller function from child controller?

I'm using Angular with ui.router and have setup a nested view. The parent view has a div whose visibility I can toggle through a function on the parent controller. I'd like to call this function from the child controller of the nested view. How would I do this?
http://plnkr.co/edit/zw5WJVhr7OKqACoJhDZw?p=preview
JS
angular
.module("myApp", [])
.controller("parent", function($scope) {
$scope.parentFunction = function() {
alert("Called a function on the parent")
};
})
.controller("child", function($scope) {
$scope.childFunction = function() {
alert("Called a function on the child")
};
$scope.parentFromChild = function() {
alert("I know this feels weird");
$scope.parentFunction();
};
})
HTML
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#*" data-semver="1.2.14" src="http://code.angularjs.org/1.2.14/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="parent">
<div ng-controller="child">
Call Parent
Call Child
Call Parent from Child
</div>
</div>
</body>
</html>
The scope on controllers is prototypically inherited I believe which means if you don't redefine a function on the scope you get the same function from the parent scope if you call it (the problem is this then makes the assumption about the context of the use of this controller though it's debatable if this is really an issue assuming you don't depend on some effect from that controller in this controller).

Resources