How can i call two controllers on one div? - angularjs

HI I need call two controllers from same div i.e div id="div1" cntr1 and cntr2,Is it possible to do?
<div id="div1" ng-controller="ctrl1">
</div>
Please help me out ..

nested controller - you can access ctrl1's field and function in ctrl2 also .You can use $parent.
<div ng-controller="ctrl1">
<div ng-controller="ctrl2">
</div>
</div>

Define a directive that has the desired controller:
angular.module(...).directive('ctrl2', function() {
return {
restrict: 'A',
scope: false,
controller: 'ctrl2'
};
});
Use as:
<div id="div1" ng-controller="ctrl1" ctrl2></div>

Related

AngularJS - Transclusion Containing Transclusion?

I am using Bootstrap UI's accordion directive. This uses transclusion under the hood. I have some logic that needs repeated, so I am trying to create a directive that wraps the accordian, which also uses transclusion.
<div>
<div accordion>
<div accordion-group is-open="isOpen">
<div accordion-heading>
<span class="glyphicon" ng-class="{'glyphicon-minus-sign': isOpen, 'glyphicon-plus-sign': !isOpen}"></span>
<strong>{{headerTitle}}</strong>
</div>
<div ng-transclude></div>
</div>
</div>
</div>
Here is the JavaScript:
application.directive('collapsePanel', ['baseUrl', function (baseUrl) {
return {
restrict: 'A',
templateUrl: baseUrl + 'content/templates/collapse_panel.html',
replace: true,
transclude: true,
scope: {
headerTitle: '#'
},
controller: ['$scope', function ($scope) {
$scope.isOpen = false;
}]
};
}]);
It should be as simple to use as:
<div collapse-panel header-title="Title">
{{scopeVariable}}
</div>
Assuming scopeVariable is in my controller, I would think its value would appear. From what I can tell, the scope belongs to the collapse-panel rather than the outer scope. It is almost like having nested transclusion directives is causing my problem.
Is there a trick to nesting transclusions like this?

Angular Directive: Isolate Scope & Transclude is true, but HTML in the directive needs to continue to bind to parent $scope

To start, I set up a JSFiddle here: http://jsfiddle.net/qLagkgt5/3/
I hope the title is clear, but basically, I am trying to use directives to help in repeatable html. In the example on JSFiddle, I am using a box directive with options for spacing and box-type.
The html that I am turning into repeatable code:
<div class="box">
<div class="box-inner">
{{CONTENT GOES HERE}}
</div>
</div>
With optional classes:
<div class="box spacing-small box-rounded">
<div class="box-inner">
{{CONTENT GOES HERE}}
</div>
</div>
What I'd like to be able to do is:
<box spacing="small" box-type="rounded">
{{CONTENT GOES HERE}}
</box>
This is obviously a very simplified set of html that doesn't necessarily need a directive, but it is just an example to illustrate what I am running into.
Now to the angular side of things...
Here is my controller:
app.controller("Ctrl", ["$scope", function($scope) {
$scope.text = "Starting Text... FOOBAR!";
}]);
And here is my directive:
app.directive("box", function() {
return {
restrict: "E",
transclude: true,
replace: true,
scope: {
spacing: "#",
boxType: "#"
},
template: '<div class="box" ng-class="{\'spacing-{{spacing}}\' : spacing, \'box-{{boxType}}\' : boxType}"> <div class="box-inner" ng-transclude></div></div>'
}
});
If I now place my directive inside html with a controller like this:
<div class="wrap" ng-controller="controller">
{{text}}
<box spacing="small">
<input ng-model="text"/>
</box>
</div>
The $scope.text that is outside the <box> is never updated when I change the input inside the box.
How do I make it so that when this directive is used, the content inside the box goes up to the parent scope rather then the isolated scope?
If I nest a box inside another box, can I also have it go up to the same parent scope?
Thanks!
I read something here on stackoverflow that immediately jumped in my head when I read your post. It said something like "If you do it without a dot you are doing it wrong..." I'll search for the article and post it here as soon as I found it but for now I think I "fixed" your code:
<div ng-app="app" ng-controller="Ctrl">
<h1><span class="grey">$scope.data.text:</span> {{data.text}}</h1>
<box spacing="large" box-type="rounded">
<h2><span class="grey">$scope.text in box directive:</span> {{data.text}}</h2>
<input ng-model="data.text" />
</box>
<box spacing="small" box-type="rounded-shadow">
<h2><span class="grey">$scope.text in different box directive:</span> {{data.text}}</h2>
<input ng-model="data.text" />
</box>
</div>
var app = angular.module("app", []);
app.controller("Ctrl", ["$scope", function($scope) {
$scope.data = {};
$scope.data.text = "Starting Text... FOOBAR!";
}]);
app.directive("box", function() {
return {
restrict: "E",
transclude: true,
replace: true,
scope: {
spacing: "#",
boxType: "#"
},
template: '<div class="box" ng-class="{\'spacing-{{spacing}}\' : spacing, \'box-{{boxType}}\' : boxType}"> <div class="box-inner" ng-transclude></div></div>'
}
});
You have to create an object and use this for databinding. I am now using "data.text" and do the binding with this expression.
Cheers,
Tim.
P.S.: There are a lot of links.
To mention only two:
AngularJS: If you are not using a .(dot) in your models you are doing it wrong?
AngularJS: dot in ng-model

Wrap content using directive and transclude

I would like to surround and input with a wrapper which contains multiple divs. I would want the input to be placed inside of the div called "my-content". I'm using a directive to achieve this, but it's not being placed inside the wrapper.
These are the templates I tried:
This doesn't work
<div class="wrapper" >
<div class="left-side" > </div>
<div class="middle">
<div class="top-side"> </div>
<div class="my-content" ng-transclude ></div>
<div class="bottom-side"> </div>
</div>
<div class="right-side"> </div>
</div>
But this works
<div class="wrapper" >
<div class="left-side" > </div>
<div class="middle">
<div class="top-side"> </div>
<input class="my-content" ng-transclude />
<div class="bottom-side"> </div>
</div>
<div class="right-side"> </div>
</div>
Directive is defined as such:
app.directive('wrapMe', function(){
return {
restrict: "A",
templateUrl: 'template.html',
transclude: true,
replace: true
};
});
So to reiterate, I would like whatever has the wrap-me directive to be placed inside the div with 'my-content' class and ng-transclude. Am I missing something here?
Plunker link: http://plnkr.co/edit/oQtWNCBBuc61bRwzDjHP?p=preview
You're almost there. Just change transclude option to element and you're done. Basically you want both the input element and its contents to be transcluded. The previous option (transclude: true) only transcludes the contents, which is empty, that's why it didn't work.
app.directive('wrapMe', function(){
return {
restrict: "A",
templateUrl: 'template.html',
transclude: 'element',
replace: true
};
});
Updated plunkr: http://plnkr.co/edit/IX0ELKR4wKOPtt2vO6FB?p=preview

AngularJS: Access models using dynamic names in template

I have a template with a lot of what is essentially duplicate code. I'd like to use a directive to include a partial template which I can manipulate for each "block" of duplicate code.
The template currently looks something like this:
<div class="column book">
<div class="header">
<input type="text" id="book_query" ng-model="book_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="book in books | filter:book_query">
{{book.name}}
</div>
</div>
</div>
....
<div class="column game">
<div class="header">
<input type="text" id="game_query" ng-model="game_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="game in games | filter:game_query">
{{game.name}}
</div>
</div>
</div>
....
And the controller just gets the data and adds it to the scope e.g.
$scope.books = data.books;
$scope.games = data.games;
What I started doing was using a directive which takes in an argument (e.g. book, game etc) so I then knew which model(s) to use. The problem I have is how to use the argument to access the model in the template? The directive itself is, currently, very simple:
<div item-column item="book"></div>
<div item-column item="game"></div>
app.directive('itemColumn', function() {
return {
scope: {
item: '#'
},
replace: true,
templateUrl: 'item_column.html'
};
});
In item_column.html, I was hoping I could just substitute the item argument, which works fine for displaying the value of the arg but not for replacing where 'book' or 'game' is used for the models e.g.
<div class="column {{item}}">
<div class="header">
<input type="text" id="{{item}}_query" ng-model="{{item}}_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in ??? | filter:{{item}}_query">
{{item.name}}
</div>
</div>
</div>
Can someone show me the best way of doing this? I don't doubt I'm going the complete wrong way about it!
EDIT: The original issue above is now pretty much fully solved using JoseM's answer below. The one outstanding issue is the on-click functions on each element no longer firing the parent scope from within the isolated scope.
My controller is laid out like so:
app.controller('ItemsCtrl', ['$scope', '$http', 'CONFIG', function($scope, $http, CONFIG) {
var items = ['books', 'games'];
items.forEach(function(item) {
$scope[item] = [];
$scope['selected_'+item] = null;
})
$scope.getItem = function(item) {
$http.get('?action=get_item&id='+item.id+'&type='+item.type)
.success(function(data) {
// update model
})
.error(function(data, status) {
// do something
});
}
}]);
$scope.getItem is no longer accessible when clicking on the item in the view, which looks similar to the following after implementing JoseM's answer:
<div class="row" ng-repeat="item in array | filter:query">
<div class="text" ng-click="getItem(item)">
{{item.name}}
</div>
</div>
Is there a simple way of making the parent scope functions available from within the isolated scope? Or is there a better place for these functions? Apologies for (what I feel are) the very basic questions - I'm still trying to get my head around Angular!
One way to accomplish what you want is by using a child scope in your directive and then doing your own "linking" of the parent scope variables using a watch on the parent scope value.
in your directive:
app.directive('itemColumn', function() {
return {
scope: true,
templateUrl: 'item_column.html',
link: function(scope,elem,attrs) {
var varName = scope.varName = attrs.item;
var parScope = scope.$parent;
parScope.$watch(varName + 's', function(newVal){
scope.theArray = newVal;
});
parScope.$watch(varName + '_query', function(newVal){
scope.theQuery = newVal;
});
}
};
});
in your template:
<div class="column {{varName}}">
<div class="header">
<input type="text" ng-attr-id="{{varName}}_query" ng-model="theQuery.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in theArray | filter:theQuery">
{{item.name}}
</div>
</div>
</div>
If you want to use an isolated scope, you could it, but then you would have to supply at least 3 attributes if you are using the same properties as above. I personally believe that using an isolated scope is a better way of doing it. See below how the isolated version is simpler:
isolated version of directive
app.directive('itemColumn2', function() {
return {
scope: {
label: '#',
array: '=',
query: '='
},
templateUrl: 'item_column2.html'
};
});
isolated version of template
<div class="column {{label}}">
<div class="header">
<input type="text" ng-attr-id="{{label}}_query" ng-model="query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in array | filter:query">
{{item.name}}
</div>
</div>
</div>
usage
<div item-column2 label="book" array="books" query="book_query"></div>
<div item-column2 label="game" array="games" query="game_query"></div>
And finally here is a sample plunker: http://plnkr.co/edit/OyEHR4ZhzYKvs4jeDfjD?p=preview

ng-click attribute on angularjs directive

I think it should be easy to use the well known angular attributes on a directive out of the box.
For example if the name of my directive is myDirective I would like to use it this way:
<div ng-controller="myController">
<my-directive ng-click="doSomething()"><my-directive>
</div>
instead of needing to define a custom click attribute (onClick) as in the example below
<div ng-controller="myController">
<my-directive on-click="doSomething()"><my-directive>
</div>
It seems that ng-click can work, but then you need to specify ng-controller on the directive tag too which I don't want. I want to define the controller on a surrounding div
Is it possible to use ng-click on a directive together with a controller defined on a parent html element?
Here is updated code. Maybe is this what you were looking for.
Html:
<div data-ng-app="myApp">
<div data-ng-controller="MyController">
<my-directive data-ng-click="myFirstFunction('Hallo')"></my-directive>
<my-directive data-ng-click="mySecondFunction('Hi')"></my-directive>
</div>
</div>
Angular:
var app = angular.module('myApp', []);
app.directive('myDirective', function(){
return {
restrict: 'EA',
replace: true,
scope: {
eventHandler: '&ngClick'
},
template: '<div id="holder"><button data-ng-click="eventHandler()">Call own function</button></div>'
};
});
app.controller('MyController', ['$scope', function($scope) {
$scope.myFirstFunction = function(msg) {
alert(msg + '!!! first function call!');
};
$scope.mySecondFunction = function(msg) {
alert(msg + '!!! second function call!');
};
}]);
Edit
Check solution that I made in jsFiddler is that what you were looking for?
http://jsfiddle.net/migontech/3QRDt/1/

Resources