Angualrjs- redirect from one controller to another - angularjs

I have two controllers. I would like to use the other controller based on a dependancy value. I am not able to set this at the $route level. How can I essentially do this on in the main controller: Is this even possible?
angular.module('app').controller('Controller1', ['importantService', function(importantService) {
if (importantService.getValue) {
// Use this other controller Controller2 instead
}
});

You could put your 2 controllers in directives and have an ng-if in the template switch between the two, something like:
app.controller('MainCtrl', function($scope, importantService) {
$scope.importantValue = importantService.getValue;
});
app.directive('myFirstComponent', function() {
return {
restrict: 'E',
templateUrl: '/same/url/for/both',
controller: function() {/*...your controller 1*/}
};
});
app.directive('mySecondComponent', function() {
return {
restrict: 'E',
templateUrl: '/same/url/for/both',
controller: function() {/*...your controller 2*/}
};
});
and in your template
<div ng-if="importantValue === 1"><my-first-component></my-first-component></div>
<div ng-if="importantValue === 0"><my-second-component></my-second-component></div>
probably not the most orthodox solution but it will do what you're asking.

Related

Angular - pass object from directive to parent scope on click

I'm using an angular directive to generate a reusable template and show some data in it. The directive also has an ng-click that should take an object and pass it to the parent controller. I'm kind of stuck, not really sure how to pass that data from the directive controller to the scope of the parent controller. I read here but the circumstances are a bit different.
The js code of the directive:
angular.module("app")
.directive('userData', function() {
return {
restrict: "E",
templateUrl: "directives/userData/userData.html",
scope: {
userObj: "="
},
controller: function($scope){
},
link: function(scope, elements, attrs, controller){
}
}
});
And this is the directive html:
<div class="style" ng-click="displayFullDetails(userObj)">{{userObj.first_name}}</div>
Parent controller:
angular.module("app").controller("parentCtrl", ['$scope', function ($scope) {
angular.element(document).ready(function () {
getDataService.getJsonData().then(function (data) {
$scope.users = data.data;
})
});
}]);

Multiple Controller As Syntax with One Directive?

I have Routes and Controllers like below
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
templateUrl : '/data/user.html',
controller : 'UserController as usr'
})
.when('/add-schema', {
templateUrl : '/data/group.html',
controller : 'GroupController as grp'
})
}])
/*Note That I dont want to use $scope*/
.controller('UserController', function($http) {
var vm = this;
vm.total_rows = 90;
})
.controller('GroupController', function($http) {
var vm = this;
vm.total_rows = 60;
});
And I want to use only one pagination Directive for all pages , smth like this
.directive('datasPagination', function() {
return {
restrict: 'E',
template: '<ul class="pagination"><li>{{total_rows}}</li></ul>'
}
});
How to get the {{total_rows}} inside my Directive given that I use Controller As Syntax with different aliases and I dont use $scope ? . Above, I use "usr" and "grp" as Alias
Regards
Try to isolate the directive scope, this is useful when you want to build a reusable component...
APP.directive('datasPagination', function() {
return {
restrict: 'E',
scope: {
rows: "="
},
template: '<ul class="pagination"><li>{{rows}}</li></ul>'
}
});
<!-- where alias is the alias defined in controllerAs syntax -->
<data-pagination rows="alias.total_rows" />
further reading here

Angularjs Is there a cleaner more "angular" way to replace a transcluded class value in a directive template?

Below is the only way i could figure out how to get a directive to pull out an attribute from its origin element, get a new value by hitting a service, and then adding that new service method return as a class in the directive template. i'm wondering if there is an alternative pattern that might be cleaner then this pattern that might use ng-class or possibly ng-transclude:
html:
<my-directive data-condition="{{hour.condition}}"></my-directive>
js:
angular.module('myApp')
.directive('myDirective', function (myService) {
return {
transclude: true,
replace: true,
scope: true,
template: '<i class="{{wiIconClass}}"></i>',
restrict: 'E',
link: function($scope, $elm, attrs){
$scope.wiIconClass=myService.getValue(attrs.condition);
}
}
});
If your function myService.getValue is synchronous, you could simply do:
<div ng-class="getClass(hour.condition)">
And in your controller:
$scope.getClass = function(condition) {
return myService.getValue(condition);
}
Alternatively, you can directly put your service within your scope:
$scope.myService = myService;
So the HTML becomes
<div ng-class="myService.getValue(hour.condition)">
In both cases, you will need to inject your service into your controller:
myModule.controller('myController', function($scope, myService) {
// this controller has access to myService
})
I would use the Directives scope parameter instead of using the Directives Attribute values. This is because when using the attributes you will need to setup a $watch to see when that value updates, with using $scope you get the benefit of the binding aspect.
As far as to respond to the best way, its hard to say without knowing your actual task. You can have Angular update the elements css class value in several different ways.
Here's a working Plunker with some small updates to your existing code.
http://plnkr.co/edit/W0SOiBEDE03MgostqemT?p=preview
angular.module('myApp', [])
.controller('myController', function($scope) {
$scope.hour = {
condition: 'good'
};
})
.factory('myService', function() {
var condValues = {
good: 'good-class',
bad: 'bad-class'
};
return {
getValue: function(key) {
return condValues[key];
}
};
})
.directive('myDirective', function(myService) {
return {
transclude: true,
replace: true,
scope: {
condition: '='
},
template: '<i class="{{myService.getValue(condition)}}"></i>',
restrict: 'E',
link: function(scope, elm, attrs) {
scope.myService = myService;
}
};
});

How to mock inline controller on directive?

When testing you can mock a controller that has been registered with angular.module(...).controller('MyCtrl') by using $controllerProvider.register('MyCtrl').
But how can I mock an inline controller on a directive?
function MyCtrl() {
}
function MyDir() {
return {
restrict: 'E',
controllerAs: 'myCtrl',
controller: MyCtrl,
template: '<div>hi</div>',
};
}
Not possible without something really hacky. Instead, declare the controller as normal and reference it from the directive by name.
angular.module(...).controller('MyCtrl')
directive:
return {
// ...
controller: 'MyCtrl',
// ...
};
This also allows you to test the controller like any other controller.
This is very late, but it actually is possible:
angular
.module( 'myModule' )
.directive( 'myDir', function() {
return {
restrict: 'A',
bindToController: true,
controllerAs: '$ctrl',
controller: MyDirController,
scope: {}
};
});
function MyDirController( ... ) { ... }
...
let myDir = $injector.get( 'myDirDirective' ); //Returns an array of registrations
let $controller = $injector.get( '$controller' );
//Since we expect only a single registration, we can use the first element
let $ctrl = $controller( myDir[0].controller, { /*locals*/}, {/*bindings*/});

Calling functions between directives

I am currently building my very first APP using angular and I find myself a bit lost, will appreciate any help regarding the following topic.
I have a single page app with two panels. The left side panel displays a list of items (let's say news), and the right side panel displays the details of any of the available news. I want to be able to click on any of the items listed on the left panel and read the details on the right panel.
A sample HTML/JS code for this model will be as followed (This code will not work as it is):
HTML:
<div id="leftPanel">
<news-list></news-list>
</div>
<div id="rightPanel">
<news-detail></news-detail>
</div>
Javascript/Angular:
var app = angular.module('app', []);
app.directive('newsList', function () {
return{
restrict: 'E',
templateUrl: 'templates/news-list.html',
controller: function ($show) {
$scope.clickAction(item){
data = ....some JSON http request...
showDetail(data);
}
},
controllerAs: 'listing'
};
});
app.directive('newsDetail', function () {
return{
restrict: 'E',
templateUrl: 'templates/news-detail.html',
controller: function ($scope) {
$scope.showDetail(data){
....
}
},
controllerAs: 'detail'
};
});
As you can see, the showDetail() function from newsDetail has to be called from the newsList directive controller above. The click action event is called from the different elements within the news list template.
The question is: ¿How can I call a function within a controller from another controller when inside a directive?
Thanks
It would probably be a better idea for you to declare a controller in a parent element of both newsList and newsDetail . Here's my suggestion:
var app = angular.module('app', []);
app.directive('newsList', function () {
return{
restrict: 'E',
templateUrl: 'templates/news-list.html',
controller: function ($show) {
$scope.clickAction(item){
data = ....some JSON http request...
$scope.showDetail(data);
}
},
controllerAs: 'listing'
};
});
app.directive('newsDetail', function () {
return{
restrict: 'E',
templateUrl: 'templates/news-detail.html',
controllerAs: 'detail'
};
});
app.controller('newsCtrl', function($scope){
$scope.showDetail = function(data){
....
};
});
And nest your directives in the parent element on which you use the ngController directive:
<div ng-controller="newsCtrl">
<div id="leftPanel">
<news-list></news-list>
</div>
<div id="rightPanel">
<news-detail></news-detail>
</div>
</div>
How about trying to add the directive you wanna associate with inside your directive as follows:
var app = angular.module('app', []);
app.directive('newsList', function () {
return{
required: 'newsDetail',
restrict: 'E',
templateUrl: 'templates/news-list.html',
controller: function ($show) {
$scope.clickAction(item){
data = ....some JSON http request...
detail.showDetail(data);
}
},
controllerAs: 'listing'
};
});
app.directive('newsDetail', function () {
return{
restrict: 'E',
templateUrl: 'templates/news-detail.html',
controller: function ($scope) {
$scope.showDetail(data){
....
}
},
controllerAs: 'detail'
};
});

Resources