I'm working with a directive.
Here is simple format of my directive:
angular.module('app',[]).directive('companylookup', CompanyLookupDirective);
function CompanyLookupDirective() {
return {
templateUrl: '<input id="foo"/>',
controller: 'CompanyLookupController',
controllerAs: 'vm'
}
}
I want to find input element with jquery in my controller (CompanyLookupController.js) like this:
var foo = $('#foo');
// decorate foo element using igniteui lib
$('#foo').igCombo({ datasource: ...});
But $('#foo') always return null. I can try to delay finding element with $timeout service to wait until element exist. But I don't want to do this so much times in my app in concern of performance.
Is there any way we can reference template elements in angularjs from a controller?
in template URL use escape character before quotes ,
templateUrl: '<input id=\"foo\"></input>'
Also i agree with #Robert Goldwein and if you absolutely have to, use link to manipulate DOM
EDIT : Help on link and compile functions.
Related
I'm trying to turn a directive into a component.
I have a value service ('path') defined on the app, which returns a path that was used to create the template url. With the directive it could be injected into the function and then used to create the template url like this:
.directive('myCustomer', [ 'path', function(path) {
return {
templateUrl: path + '/customer.html'
};
}]);
How can I pass 'path' to a component, where I have an object instead of the function?
app.component('myCustomer', {
template: `<div ng-include="$ctrl.templateUrl"></div>`,
controller: ['path', function(path) {
this.templateUrl = path + '/customer.html'
}]
});
Note: As components use isolate scope, appropriate bindings need to be added to both the component and the HTML where it is instantiated.
For more information, see AngularJS Developer Guide - Component-based application architecture.
Use component bindings to consume the value.
Refer to docs here
Thanks
Ashish
Use this.
template: '<div ng-include="$ctrl.templateUrl">'
store the value in templateUrl using component binding.
I am trying to write a simple CMS system where the content of each page is stored in a database. When the user tries to access
/pages/abc.html
through angular routing and controller to retrieve the content of that page from the database and generate abc.html on the fly. I found one way is to add a function to templateUrl to return the page:
.when('/content/pages/:name*', {
templateUrl: function(parameters) {
return '/pages/' + parameters.name + '.html';
},
controller: 'ContentCtrl',
controllerAs: 'content'
})
However the issue is I need to have abc.html already exist and then in the controller to compile the DOM content and attach it. What I am trying to do is not to have the abc.html already exist, but generated on the fly. This way I can allow my user to add xyz content and when they try to access xyz.html it will be there, without having to create xyz.html template html upfront. Is there any method I can use to achieve this.
Is there any reason you need to generate the parameters.name html file? I would think you could define the template as then pass the html into the controller. If there is a lot of repeated logic, you could make a content component or directive.
What I did for this is write a custom directive. I pass the directive an array that contain objects that correspond to ui elements. The objects are defined in JS and all have a .html() function I wrote that generates some html based on the objects properties. Then to store/restore the structure you can just JSON.stringify the object to insert it in the DB and JSON.parse to get the object back... Only tricky part is you need to store the data type as a property of the object so you can pick the right type.
The directive itself just calls the html() function on each object and concatenates the output then sets the innerHTML of the element.
I realized I could just use the template property to insert any html I want.
.when('/content/pages/:name*', {
template: function(parameters) {
return 'hello' + parameters.name;
},
controller: 'ContentCtrl',
controllerAs: 'content'
})
What you can do it pass template name as a parameter to the controller:
.when('/content/pages/:name*', {
templateUrl: function(parameters) {
return '/pages/:templateName';
},
controller: 'ContentCtrl',
controllerAs: 'content'
})
And in the controller, create the required HTML (if not existing) and then in template include the HTML using ng-include:
<div ng-include="template.url" ng-if="template.url"></div>
learning angular so some time things not clear when read article on angular. here i stuck to understand what is the usage or importance of this keywords Controller and controllerAs in directive.
code taken from here http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html
app.controller('SomeController', function () {
this.foo = 'bar';
});
app.directive('someDirective', function () {
return {
restrict: 'A',
controller: 'SomeController',
controllerAs: 'ctrl',
template: '{{ctrl.foo}}'
};
});
i like to know understand the importance of this two keywords in directive and they are controller: 'SomeController', and controllerAs: 'ctrl',
please tell me if we do not use these two keyword controller: 'SomeController', and controllerAs: 'ctrl', then what would happen or what would be worse ?
please help me to understand the usage or importance of this keywords controller: 'SomeController', and controllerAs: 'ctrl', in directive. thanks
You need the controller if you plan on referencing a controller object. This is how you hook it up.
The controllerAs allows you to create a variable that you can reference the controller with in lieu of using the $scope.
Refined answer:
<html ng-app="app">
<head></head>
<body>
<script src="node_modules/angular/angular.js"></script>
<script>
var app = angular.module('app', []);
app.directive('fooDirective', function() {
return {
restrict: 'A',
controller: function($scope) {
// No 'controllerAs' is defined, so we need another way
// to expose this controller's API.
// We can use $scope instead.
$scope.foo = 'Hello from foo';
},
template: '{{foo}}'
};
});
app.directive('barDirective', function() {
return {
restrict: 'A',
controller: function() {
// We define a 'vm' variable and set it to this instance.
// Note, the name 'vm' is not important here. It's not public outside this controller.
// The fact that the 'controllerAs' is also called 'vm' is just a coincidence/convention.
// You could simply use 'this.bar' if you prefer.
var vm = this;
vm.bar = 'Hello from bar';
},
// This allows us to reference objects on the controller's instance by
// a variable called 'vm'.
controllerAs: 'vm',
// Now we can reference objects on the controller using the 'controllerAs' 'vm' variable.
template: '{{vm.bar}}'
};
});
</script>
<div foo-directive></div>
<div bar-directive></div>
</body>
</html>
One of its main advantages, especially if you're new to AngularJS, is that it ensures proper data binding between child scopes.
Just play around with this code sample and try to notice something strange:
angular
.module('myApp', [])
.controller('MainCtrl', ['$scope',
function($scope) {
$scope.truthyValue = true;
$scope.foo = 'hello';
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainCtrl">
<p>Start by writing something in the first input. Then write something in the second one. Good job, you've broke AngularJS!</p>
1.
<input type="text" ng-model="foo">
<div ng-if="truthyValue">
2.
<input type="text" ng-model="foo">
</div>
<div>$scope.foo: {{ foo }}</div>
</div>
The reason behind it is that ngIf creates a child scope which inherits from the parent scope. You're basically changing the value inside ngIf's scope which doesn't affect the value from its parent scope.
Finally, I consider controllerAs syntax an important AngularJS best practice. If you get accustomed to it early in your learning process, you'd be avoiding a lot of head-scratching wondering why your code doesn't work, especially when everything seems in order.
You don't need to use both controller and controllerAs. You can use the shorthand:
controller: 'SomeController as ctrl'
The relationship is that a new instance of the controller is created and exposed to the template using the instance handle you provide as ctrl.
Where this comes in handy is if you are using nested controllers -- or using multiple instances of a controller in a view.
UPDATE TO ANSWER COMMENTS
You do not need to use controllers with AngularJS directives. Infact as of AngularJS 1.5 you should probably only use controllers when creating components rather than directives.
Directives and Components are conceptually similar. Up until AngularJS they all components would be defined as a directive.
In many ways a directive interacts with an element (like ng-href) or events (like ng-click).
The simplest way to differentiate Components and Directives is a Component will have a template.
Can't I just create a component using the directive link method?
You can, but I wouldn't recommend it unless you have a good reason. Using controllers allows you to use object oriented classes or prototypes to define the action behaviors with the template and user.
As well these controllers are extremely more easy to unit test than the directive link functions.
Check out this plunkr code
Here is my simple Directive code:
angular.module('app', [])
.directive('someDirective', function () {
return {
scope: {},
controller: function ($scope) {
this.name = 'Pascal';
$scope.color = 'blue';
},
controllerAs: 'ctrl',
template: '<div>name: {{ctrl.name}} and Color: {{color}}</div>'
};
});
And The HTML
<body ng-app="app">
<some-directive />
</body>
So, as you can see, if you need to access some variable which were defined against this keyword in the controller, you have to use controllerAs. But if it was defined against $scope object you can just access it with its name.
For example, you can get the variable color just by using {{color}} as it was defined against $scope but you have to use {{ctrl.name}} as "name" was defined against this.
I don't think there really is much difference, as this answer says,
Some people don't like the $scope syntax (don't ask me why). They say
that they could just use this
Also from their own website you can read the about the motivation behind this design choice,
Using controller as makes it obvious which controller you are
accessing in the template when multiple controllers apply to an
element
Hope it helps.
I am new to AngularJs and struck with an issue. I have "index.html" where I need to have the main section loaded via the <div data-ng-view=""></div>. Now, the data inside the view will be populated by the controller using the below code
.when('/',
{
controller:'controllers.IndexCtrl',
templateUrl:'/partials/index-partial.html'
})
Inside the index-partial.html file I have used the custom directive linke below:
<custom-carousel/>
The code for the carousel is below:
myApp.directive('customCarousel', function() {
return {
restrict: 'E',
replace:'true',
templateUrl: "/partials/carousel.html",
link: function(scope, element, attrs) {
$('.my-list').click(function(){
$('.my-list').removeClass('active');
$(this).addClass('active');
});
}
};
});
The issue with the above approach is that the jquery code inside the directive gets called twice and hence the toggling of the selected li does not work.
I have below questions:
Is the jquery function inside the directive called twice because its called from the partial and once again during the ng-view?
Whats the reccommended way of handling this scenarios?
Whats the best approach to fix this issue. If I remove the templateUrl from the controller and directly use the custom-carousel inside the html, this works perfectly but I want to load the directive using the ng-view and not directly in the index.html file.
Please let me know the best approach to solve this issue.
I have a route defined as
$routeProvider.when('/:culture/:gameKey/:gameId/closed', { templateUrl: '/templates/tradingclosed', controller: TradingClosedCtrl });
I would like angular to include the "culture" parameter when requesting the template somehow, so I can serve a translated template.
Is this possible?
If I'm reading this correctly you'd like to somehow use the culture parameter from the url route to determine which location to retrieve your template.
There may be a better way but this post describes retrieving the $routeParams inside a centralized controller with ng-include to dynamically load a view.
Something similar to this:
angular.module('myApp', []).
config(function ($routeProvider) {
$routeProvider.when('/:culture/:gameKey/:gameId/closed', {
templateUrl: '/templates/nav/urlRouter.html',
controller: 'RouteController'
});
});
function RouteController($scope, $routeParams) {
$scope.templateUrl = 'templates/tradingclosed/' + $routeParams.culture + '_template.html';
}
With this as your urlRouter.html:
<div ng-include src="templateUrl"></div>
You can define the controller you want to load in your views using ng-controller and access the $routeParams for the additional route parameters:
<div ng-controller="TradingClosedCtrl">
</div>
I've posted similar question with working Plnkr example of solution like #Gloopy suggested.
The reason why you can't implement that without ng-include is that routing is done in 'configuration' block, where you can't inject any values (you can read about these blocks in Modules documentation, section Module Loading & Dependencies
If you want not to introduce new scope, you can replace ng-include with my stripped version of ng-include directive, that do absolutely same that ng-include does, but do not create new scope: source of rawInclude directive
Hope that solution will satisfy your use case.