AngularJS : pass ng-model from directive component to controller - javascript

Inspired by angular ui, I want to create front-end library as a pieces of component, all as an angularjs directive. So that the user can simply put directive with some configurations and get the desire result of component.
So this is how the directive will look like.
<date-picker
date-format="MM.DD.YYYY HH:mm"
enable-navigation
date-picker-id="datetimepicker2"
date-picker-model="myModel1">
</date-picker>
For the usage, the idea is that it could be wrapped by user-created controller and the controller can reach the directive scope like this.
<div ng-controller="myController">
<date-picker
...
date-picker-model="myModel1">
</date-picker>
</div>
(The reason I use component-name-model is because the component directive template might have more than one model) And the code in controller would be
angular.module('myApp').controller('myController',['$scope', function($scope) {
$scope.myModel1; //this scope binds to the datepicker template scope
}]);
Since I'm pretty new to angularJs, my questions are follow.
How to make the controller reach the directive scope with this syntax ? In my case, It seems that the controller didn't notice about directive scope (see my code in plunker)
Right now I'm also stuck with passing model to the template. as you can see in directive I've define date-picker-model="myModel1" and then directive will catch attrs and pass it to template like this
if('datePickerModel' in attrs){
$scope.datePickerModel = attrs.datePickerModel;
}
and when I'm using expression on templateUrl, ng-model="{{datePickerModel}}" doesn't work
The code is quite long so I would suggest you the check out my plunker
Thank you :-)

take a look at the scope parameter by creating your directive. There you can assign your 2-way binding between the controller and the directive's scope.
http://plnkr.co/edit/ngdoc:example-example85#snapshot?p=preview
<my-customer info="igor"></my-customer>
angular.module('docsIsolateScopeDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
$scope.igor = { name: 'Igor', address: '123 Somewhere' };
}])
.directive('myCustomer', function() {
return {
restrict: 'E',
scope: {
customerInfo: '=info'
},
templateUrl: 'my-customer-iso.html'
};
});
also documented here: http://docs.angularjs.org/guide/directive
be also aware of the beginning symbol '=' or '#'!

Related

AngularJs create templates directive

I would like create directive with more templates.
And selected template depends on some value (like template-type).
Then if I invoke my directive in html page, and change type template-type, need changed html template.
Like this:
<template-factory template-type={{foo}}></template-factory>
I think what I can created one html template that contains all my templates, and select from ng-if help. But I think what it is not very well.
Help me please, select best solutions for this task.
Interestingly in a directive you can pass a function as your template which can then return a string which is used for the template.
Take a look at What are the benefits of a directive template function in Angularjs? to see how this is done and the pros/cons.
From the angular docs:
angular.module('docsTemplateUrlDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
templateUrl: function(elem, attr){
return 'customer-'+attr.type+'.html';
}
};
});

How can I create a directive that will style data with transcluded HTML

I have what I believe is a very simple desire for a directive: to take an array or object as a directive attribute and then allows the user of the directive to decide how to format/style the data (assume that the directive is more complex than I have outlined here and that it allows further manipulation of the data).
A non-functional example is as follows:
The directive
angular.module('app').directive('myDirective', () => {
return {
template: '<h2>Your data:</h2><div><ng-transclude></ng-transclude></div>',
restrict: 'E',
transclude: true,
scope: false,
link: ($scope, $element, $attrs) => {
$scope.people = $attrs.data;
// Assume some processing on the people data can occur here
},
controller: ($scope, $element, $attrs) => {
$scope.people = $attrs.data;
// Also assume that it can happen here
}
};
});
The view
<my-directive data="[{name: 'Tyler'}, {name: 'Mike'}, {name: 'John'}]">
<ul>
<li ng-repeat="person in people">{{person.name}}</li>
</ul>
</my-directive>
This doesn't work and I don't know why such a seemingly simple and contrived implementation wouldn't work. Any suggestions?
The markup passed to ng-transclude is already parsed before it's transcluded into the directive. Meaning it's accessing things on the scope outside your directive only. Since you specified scope: false it's true that the directive shares the outer scope, however you don't define scope.people until the link or controller functions run which would be after the transcluded markup was transcluded.
Angular sets up a "transclusion scope" which initially inherits from the outer scope so you have access to things in that context. However, to avoid scopes not getting destroyed when the directive scope is destroyed Angular actually replaces $parent with the directive's isolate scope.
In other words, you should be able to access directive scope data via the $parent property.
<my-directive data="[{name: 'Tyler'}, {name: 'Mike'}, {name: 'John'}]">
<ul>
<li ng-repeat="person in $parent.people">{{person.name}}</li>
</ul>
</my-directive>
http://codepen.io/Chevex/pen/eJKBgj?editors=1010
One thing i see you can do here is pass the data in through the directive's scope so it can be referenced as an object, not a string:
scope: {
people: '='
},
then you can do all the manipulation you want to in the link/controller of your directive and it'll be reflected in the transcluded markup.
take a look at this plnkr for an example: http://plnkr.co/edit/XK8YlcdeZ26nkhyopLb1?p=preview

JS - AngularJS - Get data of an directive from a controller

I´ll give my best to make my problem understandable:
I have a directive. This directive handles/alters also some data it displays. Now I was wondering how I can access these data from a parent scope e.g. the controller. I am currently getting access to the scope by selecting the element and ask for the corresponding scope:
element.scope()
It works fine but it occurs to me that this is kind of a - lets say - unconventional or odd way to get the scope of an directive.
I apologize for my english (I still practicing) and hope you guys can help me. Thank you in advance :)
OK, Based on the comments your directive is some kind of a form. There are two approaches for controlling the data inside a directive:
Parent controller of a directive should control the data. In that case, Data of each directive is unique and does not share between all directives.
The directive itself should control the data. Which it means the data will be shared in all directives, and if You change one, another will be changed too.
I go with the solution number 1 which is more preferable in my guess. Let's say your template of directive is something like this,We call it template.html:
<form name="directive_from" ng-submit="submit_form()">
<input type="text" ng-model="form.name" name="username" placeholder="username"><br>
<button type="submit">Submit</button>
</form>
Because of the time,I skipped validation but you can do that easily :)
And the directive:
angular.module('app')
.directive('formDirective',function(){
return {
restrict: 'E',
templateUrl: 'template.html',
scope: {
form: '=formData',
submit_form: '#formFunc'
},
controller: ['$scope', function($scope) {
//some extra logic or binding if you need
}
}
})
OK,Now our directive which we call it formDirective accepts two parameters:
formData which is an object and holds user inserted data.
formFunc which is a function for submitting the form.
Now parent controller:
angular.module('app')
.controller('MainCtrl', ['$scope', function($scope) {
$scope.form_object = {};
$scope.submit_it = function() {
//Do whatever you like with the $scope.form_object
}
}
And let's see the view:
<div ng-controller="MainCtrl">
<form-directive form="form_object" form-func="submit_it()"></form-directive>
</div>
That's it! It's so simple example that I believe you can customize it by your needs,But the main logic for controlling the data is something like that. for example you can pass a function for ng-change on the input field or add more input fields or...
#lilly: I think you you are looking for data exchange between the parent scope and isolated scope which is possible via '='
Here is the working fiddle
angular.module('App', [])
.controller('Main', ['$scope', function ($scope) {
$scope.exchange = {};
$scope.exchange.value = "initialized by controller";
}])
.directive('inputValue', function($timeout) {
return {
restrict: 'A',
scope: {exchangeValue: '='},
link: function(scope, element, attrs) {
$timeout(function(){
scope.exchangeValue="changed by directive";
},2000);
}
};
});
http://jsfiddle.net/tiru/dJty6/43/

Understanding angular controllers Vs directives

I'm fairly new to angularjs. Im trying to understand why it's better to use this directive, compared to just using the controller. Both examples output the same value.
Directive Example:
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
Markup:
<div ng-controller="Controller">
<div my-customer></div>
</div>
Controller Example:
angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
Markup:
<div ng-controller="Controller">
Name: {{customer.name}} Address: {{customer.address}}
</div>
Maybe I just don't fully understand directives either.
At work, we use a simple exercise to see if we need a directive or not.
If a certain snippet is used more than once, we turn it into a directive.
A directive also gives a chance to add less clutter to your templates.
angular.module('DocsSimpleDirective', [])
.controller('DocsController', [function() {
this.customer = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
}])
.directive('myCustomer', function() {
return {
scope: true
restrict: 'EA',
controller: 'DocsController',
controllerAs: 'docsCtrls',
templateUrl: 'assets/template/my-customer.directive.html'
};
})
;
would allow your template to be defined as:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Angular test</title>
</head>
<body ng-app="DocsSimpleDirective">
<my-customer></my-customer>
</body>
</html>
and your directive as:
<article>
<strong>{{ docsCtrls.customer.name }}</strong><br>
{{ docsCtrls.customer.address }}
</article>
Personally, I try to refrain from using $scope to bind data to. If somebody else starts to read your code, a magical customer, defined in some controller somewhere on the scope is a lot harder to identify than a variable on a certain controller.
Isolating your $scope can be useful (by defining scope: true) to use a a default value. If you need to stop isolating your directives, it should be something you thought about, not because it's the default value.
When you don't isolate a scope it inherits all values that are defined in the $parentScope this is useful when nesting directives, where all directives should know which parent they originate from. This has a very distinct danger, you could manipulate data in the parentscope that shouldn't be manipulated.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
Other thing you need to set scope:true
.directive('myCustomer', function() {
return {
scope:true,
template: 'Name: {{customer.name}} Address: {{customer.address}}'
};
});
REFER THIS DOC
There are multiple possible ways of how to bind functionality to template, some are better than others.
BAD - use ng-controller attribute directly in html template to
bind controller function to it
BETTER - use ngRoute or ui-router to specify routes/states or your application and there you can specify controller and template per route/ state
BEST - use directive definiton object where you can again specify both controller and template to bind them together and then use directive inside of templates and routes.
The third example is than flexible in such a way that you can use directive just in any other template like <div my-directive></div> but also in any router as a inline template like: template: '<div my-directive></div>'
The third approach is the best because it's going in direction of components which are the future (because of React, Angular 2.0 and Webcomponents). I wrote a blog post and created a sample github repository ilustrating these concepts.
Controller:
A Controller is used to augment the Angular Scope.
When a Controller is attached to the DOM via the ng-controller directive, Angular will instantiate a new Controller object, using the specified Controller's constructor function.
controllers use to:
Set up the initial state of the $scope object.
Add behavior to the $scope object.
Do not use controllers to:
Manipulate DOM — Controllers should contain only business logic.
Format input — Use angular form controls instead.
Filter output — Use angular filters instead.
Share code or state across controllers — Use angular services instead.
Directives:
At a high level, directives are markers on a DOM element (such as an attribute, element name, comment or CSS class) that tell AngularJS's HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children.
Angular comes with a set of these directives built-in, like ngBind, ngModel, and ngClass.
you can create your own directives for Angular to use.
Generally directives are used to:
inject or wrapping existing thing.
Reuse same things in different palce
can inject in DOM element as attribute, element, comment or class
so if you need to reuse the same dom or logic in different place then you should use directive instead of controller.
Also you can access parent controller object from inner directive
Like:
<div data-ng-controller="mainController">
<p>hello world</p>
<some-directive></some-directive> // inject directive as element
</div>

Isolate scope doesn't work the way I think it should

I have a fundamental misconception about isolate scopes and I can't figure out what it is.
I have a controller and directive:
.controller('MyCtrl', [
'$scope',
function($scope) {
$scope.zed = "ZZZZZ";
$scope.zz = function() {
return "yep";
};
}])
.directive("myDirective", function() {
return {
restrict: "AE",
controller: "MyCtrl",
templateUrl: 'a/path/to/my_template.html',
scope: {
z: '#'
}
};
and the template:
<div>***{{z}} {{zz()}} ^^^ {{zed}} </div>
and the use of the directive:
<div my-directive z="yabba"/>
When I run this app, the value of 'yabba' is displayed for z. I'm good with that. The isolate scope makes this possible. However, the template reaches right into the $scope and is able to run a function and grab a scalar (zed and zz). I don't want that. The controller needs access to $scope since the model upon which I'll eventually operate has to be assembled from $scope data.
My desire is to limit the directive to as little information as possible.
I would like the $scope to be available to the controller but not the directive. I want the directive to have to gets its data from the controller exclusively. I tried to add z and zed to the isolate scope but this did nothing helpful.
How can I do this? Or, is my approach simply foreign to Angular and bad? If so, that's cool, please explain to me the better approach. And, please, use small words.
You are stepping on your toes by including your controller in the directive. Just delete this line from your directive and it will behave as you guessed: controller: "MyCtrl",
Here is a plunker to mess around with. You can see that your isolated scope is working as it should with the line commented out. Just un-comment that line again and see how you now have access to the controller scope.
.directive("myDirective", function() {
return {
restrict: "AE",
// controller: "MyCtrl", REMOVE THIS LINE!!!
templateUrl: 'a/path/to/my_template.html',
scope: {
z: '#'
}
};
Plunker playground with your code
By the way, there is nothing foreign in your code. Isolated scope is a great feature to use with custom directives. There are many ways to work with Angularjs 1.+. This may not be the case when Angularjs 2.0 is released. In your example, the controller is not needed within the directive. I rarely include controllers, and I most always isolate scope. Good luck! Hope this helps.

Categories

Resources