I have a simple tab directive and I need a way to create custom routes by this directive attributes. I know I can create routes by app.config( function ($stateProvider) {...} ), but it doesn't work inside link directive function. Is there any way to do it?
UPDATE: made simple example what I mean
https://plnkr.co/edit/ZNDcZc217H2PRVHYWLA7?p=preview
myApp.directive('navTab', ["$compile", function ($compile) {
return {
restrict: 'E',
link: function (scope, element, attrs) {
myApp.config( function ($stateProvider) {
$stateProvider.state({
name: attrs.sref,
url: attrs.sref,
template: 'Hello!'
});
});
element.replaceWith('<a ui-sref="'+attrs.sref+'">Hello '+attrs.sref+'</a>');
$compile(element.contents())(scope);
}
}
}]);
Related
Note: ui-grid is name of my custom grid. Sorry about the confusion.
I have a custom directive which will have a child custom directive and will be called in this fashion in the html.
<ui-grid resource="/api/data.json">
<ui-gridcolumns>
</ui-gridcolumns>
</ui-grid>
When the child directive is enclosed within the parent directive, the console statements do not print, but when the child directive is outside of the parent directive, it prints console.log just fine. Any insight into how to make it work with the child directive within the parent directive is appreciated.
parent directive:
module.exports = function () {
return {
restrict: 'E',
templateUrl: 'app/ui-grid/grid.template.html',
link: function (scope, element, attrs) {
console.log('linked Grid');
},
controller: ['$scope', function ($scope) {
$scope.onthescreen = 'test value';
}]
};
};
Child directive:
module.exports = function () {
return {
restrict: 'E',
templateUrl: 'app/ui-grid/gridcolumns/grid.columns.template.html',
link: function (scope, element, attrs) {
console.log('linked Grid Columns');
},
controller: ['$scope', function ($scope) {
console.log('calling Grid Columns');
}]
};
};
The entire code base is in git for reference.
https://github.com/eshrinivasan/angular-gulp-browserify-boilerplate
To achieve desired behavior use transclusion:
config:
restrict: 'E',
templateUrl: 'app/ui-grid/grid.template.html',
link: function (scope, element, attrs) {
console.log('linked Grid');
},
controller: ['$scope', function ($scope) {
$scope.onthescreen = 'test value';
}],
transclude: true
and somewhere in template:
<div ng-transclude>
child directives will be placed here
</div>
I have a search box which I want to use as a custom directive. This is the code for it :
(function(angular) {
'use strict';
angular.module('searchApp', [])
.directive('searchBox', function () {
return {
restrict: 'E',
transclude: true,
scope: {
'btnclick': '&onClick'
},
link: function(scope, elem, attrs) {
});
});
},
templateUrl: 'search-box.html'
}
});
})(window.angular);
In the link part, I need a function that has some JSON data. And then, a directive should have a controller that invokes that function and passes it to the parent scope.
Please show me code for the link function and the controller.
I'm trying to inherit an attribute from a parent custom directive with isolate scope. In the example below, I want to be able to access the api attribute on myParent from the myChild controller or link function. My end goal is to inject an instance of the api that can be accessed by the children and from the view controller.
<my-parent api="parentInstance1">
<my-child ng-repeat="field in ::data"
ng-attr-src="{{field.src||undefined}}"
</my-child>
</my-parent>
<my-parent api="parentInstance2">
<my-child ng-repeat="field in ::data"
ng-attr-src="{{field.src||undefined}}"
</my-child>
</my-parent>
A simplified version of both directives looks like this
app.directive('myParent', function () {
return {
transclude: true,
restrict: "E",
scope: {
api: '=?'
},
template: '...',
controller: function ($scope, $attrs ) {
// foo is injected from a factory instance
function foo ( ) {
}
$scope.api = {
foo: foo
}
},
link: function ($scope, $element, $attr) {
}
}
});
app.directive('myChild', function () {
return {
require: "^myParent",
restrict: "E",
scope: {
api: '=?'
},
template: "...",
controller: function ( $scope ) {
// I want to access $scope.api in link or controller
},
link: function ($scope, $element, $attr) {
// I want to access $scope.api in link or controller
}
}
});
I can't access $scope.api from the child directive but $scope.parentInstance1 and $scope.parentInstance2 are visible. I realise I can just explicitly declare but I'd rather understand how to do it correctly.
I dont know why you are referencing parentInstance1 and parentInstance2 on my-parent but the attributes on my-child are in myParent's $scope so you can reference the actual $scope.api object that is on myParent's $scope in the attributes of the my-child directive tag and then reference the name of the attribute in the isolate scope definition of the myChild directive.
<my-child inner-api="api"></my-child>
.. and then in the child directive...
app.directive('myChild', function () {
...
scope: {
innerApi: '=?'
}
...
controller: function($scope) {
$scope.innerApi // <- accessible in the controller
}
Heres a simplified fiddle...
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;
}
};
});
Here is a directive that is loading new Template from file:
.directive('candidatesFilter', function(){
return {
resctict: 'E',
replace: true,
templateUrl: 'views/directives/filters/AAAA.html'
}
})
Next HTML-element calls this directive from the other HTML-Template (e.g. xxx.html):
<candidates-filter></candidates-filter>
There is next controller for this parent Template (xxx.html):
app.controller('candidatesController', function($scope, $location ){
$scope.addPeson = function() {
$location.url('/candidate/0');
};
});
Method addPerson() is not accessible inside the Directive's template AAAA.html, because
data-ng-click="addPerson()"
is not working there. How to change the Directive to make addPerson() method available inside the directive's template?
TEMPORARY Solution
I fixed this issue by next solution
.directive('candidatesFilter', function(){
return {
resctict: 'E',
replace: true,
templateUrl: 'views/directives/filters/AAAA.html',
controller: function(){
$('button.add').on('click',function(){
location.hash = '#/candidate/0';
});
}
}
})
If I understand the problem correctly:
You can pass a function into the directive for it to use
<candidates-filter></candidates-filter>
becomes
<candidates-filter add-candidate="addPerson()"></candidates-filter>
and the directive definition changed as follows:
.directive('candidatesFilter', function() {
return {
resctict: 'E',
replace: true,
scope: {
addCandidate: '&addCandidate'
}
templateUrl: 'views/directives/filters/AAAA.html'
link: function(scope, element, attrs) {
scope.someFunctionInDirective = function() {
scope.addCandidate();
}
};
}
})
Alternatively you can call it with the ng-click like normal from the button
Hope this helps clarify it?