Provide default template inside AngularJS custom directive - angularjs

I'm trying to update a custom directive in AngularJS - it currently has a fixed template specified within the code (using the template: attribute).
I'd like to allow the user to optionally provide their own template instead, using the templateUrl: attribute.
My problem is how to provide a fallback - I can't use both template and templateUrl in the same directive. This is required to allow backwards compatibility.
I've tried using a function for templateUrl, but returning HTML isn't a runner there.
Any other suggestions?

If you use function in templateUrl, you are suppose to provide "template identifier" Angular first looks into the template cache, if its not found it tries to do asynchroneous request for the resource of the same url.
So you can simply put your default template into the file and just return its identifier as default.
By the way, if you are using templateUrl and html in separate files, be sure to use some kind of tool like https://www.npmjs.com/package/ng-html2js in the build process.

Related

angular Syntax Error: Token 'src' is an unexpected token

in this plunkr example, I am simply trying to create my own ng-include directive that just replaces the src attribute automatically with something else (add some extra params).
When the 'replace' attribute on the directive is 'true', it breaks with the error above. If I set it to 'false', everything is ok but then I get an extra level of nesting in my DOM, which I'm trying to avoid...
The expression that fails is:
template: '<ng-include src="src | srcizer"></ng-include>'
Is there any way to use replace=true and still create this kind of ng-include alternative?
This should work:
template: '<ng-include ng-src="src | srcizer"></ng-include>'
I don't understand what are you trying but seems you don't need to use ng-include since you can use templateUrl instead of template in directive. This allows to store angular templates like common html in html files.
Here is your updated plunker
Pay attention to templateUrl: 'mytemplate.html' this update in your directive.
And now about replace:true. According to angular documentation its deprecated, so avoid using it.
replace ([DEPRECATED!], will be removed in next major release - i.e. v2.0)

Angular Directive not executing on UI Bootstrap Modal open

I have a one-page site that I am building out and this is my first time using Angular on a site. Building it on top of Laravel too for the backend but that is beyond the scope of this question.
I need to be able to open a modal on a main page view which will add a new resource (e.g. a new client) or edit a resource. I want to somehow get the form's html inside the modal body when the $uibModal.open()'s controller is called and set the $scope.modalBody equal to the injected items.modalBody (the only way this works is if I use:
$scope.modalBody = $sce.trustAsHtml(items.modalBody);
The only problem now is that anything inside the HTML body, Angular will not use it's magic and do any data-binding. It is still in the raw form of
{{ object.property }} or since I'm using Laravel and avoiding conflict with the Blade template engine:
<% object.property %>
See screenshot:
screenshot
I have been banging my head against the wall on this one...I have tried putting $scope.$apply() in my directive and my controller, neither of which worked. I have a feeling that is the source of my problem though. I have also tried making the html just a <new-client></new-client> directive and using templateUrl: 'views/clients/add.php' which would be ideal, but the template is not being included inside the <new-client></new-client>.
I'm using ui-bootstrap 0.14.3 and Angular 1.4.8.
Could this be a bug? Or am I doing something wrong? Anyone have a better way of getting a form into my modal? Let me know what code you want to see so I don't clutter this post with unnecessary code blocks.
I have come across a similar issue with using jQuery's AJAX to receive template strings and append it to a server.
So when HTML is added via jQuery, bound html string, etc., angular doesn't know it needs to automagically compile this data.
What you need to do is use the $compile service, to $compile your html and then attach the correct $scope to it:
`$compile('jQuerySelectorReturningHtmlOrAnHTMLStringThatNeedsToBeCompiled')($scope);`
There are multiple examples in Angulars Documentation for $compile that can give you an idea of what is happening. I think by what you have described the same thing is happening here in your situation.
The key is to call this $compile service function after the html has been bound to the page.
EDIT:
There are a few other options based on some comments, that will serve as a viable solution to rendering this content on your view. For example a directive that takes a string attribute representing the HTML string of your desired view.
1. Modify your directive template in the compile step:
You have the ability to modify your template before the directive compiles and binds any attributes to it, to that directives scope:
app.directive('myAwesomeCompileStepDirective', [myAwesomeCompileStepDirectivef]);
function myAwesomeCompileStepDirectiveFn() {
return {
restrict: 'EA',
compile: function compileFn(tAttrs, tElement) {
//Here you can access the attrs that are passed into your directive (aka html string)
tElement.html(tAttrs['stringThatYouWantToReplaceElementWith']);
return function linkFn(scope, element, attrs, controller, transcludeFn) {
//if all you want to do is update the template you really don't have to do anything
//here but I leave it defined anyways.
}
}
}
}
You can view a file I wrote for a npm component which uses this method to modify my directive template before it is compiled on the page & you can also view the codepen for the complete component to see it in action.
2. Use $compile service to call $compile in link function using directive attrs.
In the same way as the aforementioned method, you can instead inject the $compile service, and call the function mentioned above. This provides a bit more work, for you but more flexibility to listen to events and perform scope based functions which is not available in the compile function in option 1.

Overriding the way how templates are retrieved using templateUrl property

I am searching for way how to (at one place) override the way how templates are retrieved from templateUrl property (in routes definition, directives, ng-include, etc).
i.e. I want to change url of template for every template request by adding base URL at the beginning.
I was experimenting with template $TemplateRequestProvider but it seems it works only for executing directives and has no influence for routes and its template retrieving.
Has anybody experience with it?
I want to change url of template for every template request by adding base URL at the beginning.
Use the following process:
Assign the base URL to a variable in a JavaScript file
Prepend the variable name to the existing templateURL values
Expand the value via a build script or a provider
References
How to set AngularjJS base URL dynamically based on fetched environment variable?
ngAppRoot

pass parameter to Angular directive template function post-post-link, using $scope, GET or whatever

I am trying to write a directive that will format content for modal display (using Bootstrap classes) if given a certain parameter, and as standard view if not. I have this working for a view loaded directly, toggling on a URL param (?modal) available to $routeParams and/or $location.
I want to use this toggle-able template as a "pipe" for other templates. However, the intended content URL will never be the visible URL when used as a modal. I can't get it working when loading the view with $modal.open or ngInclude, because $routeParams/$location has data for the including page, not the included one.
I put this in a Plunker, but because Plunker also doesn't provide the URL param, the modal view isn't available.
Does Angular provide a means to change the template or templateUrl much later in the process? For example, could I use $scope, either from a controller or on the directive, itself?
Clarification: The goal here is to have one template/partial for each component, with that template used either as a standalone or a modal, based on some switch. The _modal and _alone partials in the Plunker convert the component template into the desired state.
$modal.open takes a single object parameter one of the properties of this config parameter is templateUrl
http://angular-ui.github.io/bootstrap/
So you can create the config object and open the modal with any template you need.
Dan Wahlin uses this technique for a dialog service and then in this article goes on to demonstrate a full modal service
http://weblogs.asp.net/dwahlin/building-an-angularjs-modal-service
There were a couple of issues with your code:
First of all the use $routeParams if you don't use ngRoute's $routeProvider.
In your case, it might be easier to use $window.location.search (and compare it against ?modal).
That said, in order to properly display a Bootstrap modal, you need Bootstrap's JS file (which in turn requires jQuery) and you also need to create the modal (e.g. by calling $('.modal').modal()).
Take a look at this modified demo.
For better intergration with Angular's components, you might want to look into UI Bootstrap.

Dynamically change template of directory

I'am new to Angular.js, and I am trying to use different templates inside a directive for different clients.
The problem is, I have three templates for three kinds of clients, and I want to use different templates for my directive based on the result of client type after detection
The results I found after Googling was all about adding attributes to the directory tag, but by the time I have detection result ready, the template is already compiled.
Any suggestions?
You could inject a variable into your directive to look in a different directory for the template.
myApp.directive('testDirective', [
'clientType', function(clientType) {
return {
...
templateUrl: '/templates/' + clientType + '/test.html'
};
}
]);
Then you can set the constant 'clientType' outside of your app and pass it in as a constant.
myApp.constant('clientType', 'mobile'); // Some type of function to determine this
You may need to manually bootstrap your app in order to use this effectively though. I am doing something similar in production code to control where templates are loaded from.
You could use ngSwitch within your directive template.

Resources