I am using angularjs + MVC.
I am creating some angularjs directives. I want to put templates inside the View folder.. I think is a cleaner solution than having another folder that contains the template. Following the structure of my solution, I think that is nothing special:
Root
Areas
Scripts
Directives (here I have angular directives)
Views
Shared
Templates (here I have the templates of the directives)
Here an example of directive:
angular.module('qbDirectives', []).directive('qbPreloader', ['$document', function ($document) {
return {
templateUrl: '/Views/Shared/Templates/qbPreloader.html',
link: function (scope, element, attr) { ... }
...
};
}]);
As you can see, the template is an HTML file, not a CSHTML.. When I run my application I obtain this client error:
Failed to load resource: the server responded with a status of 404 (Not Found) http://localhost:52746/Views/Shared/Templates/qbPreloader.html
The physical path is correct but the template is not found. I think the problem is that MVC can access the View folder just with routing, so MVC need a controller to load the resource.
I do not want to do a server side call to obtain the template so I am trying to ignore the route.
In my global.asax I wrote
routes.IgnoreRoute(
"{*staticfile}",
new { staticfile = #".*\.(jpg|gif|jpeg|png|js|css|htm|html|htc)$" }
);
or
routes.IgnoreRoute("Views/Shared/Templates/{file}.html");
Buth nothing works. I still have the same problem.
How do I have to ignore the route correctly?
Thank you
Related
I am trying to cache $templatecache as my html is coming from controller as string than I just put it in to cache using $templatecache but when i am trying to include it in HTML using following statement than its showing me 404 not found error in console.
http://local.mydomain.com/myaccount/dqs.html 404 (Not found)
"<div id="dqs" ng-include="'dqs.html'" class="form__main" set-height></div>"
Angular code :
$templateCache.put('dqs.html', filteredFormHtml);
As you are adding your template in html, you need to first cache that template by using $templateRequest service.
$templateRequest('/myaccount/dqs.html').then(function (filteredFormHtml) {
$templateCache.put('filteredFormHtml', filteredFormHtml);
});
Once the template is cached, you can use it anywhere in your template using ng-include
"<div id="dqs" ng-include="'dqs.html'" class="form__main" set-height></div>"
Below are the user links for better understanding on $tempalteCache Service
1) https://docs.angularjs.org/api/ng/service/$templateCache
2) https://thinkster.io/templatecache-tutorial
I have a gulp setup that puts all my html in template cache for faster access in angular. I'm trying to add a service worker to my project, using sw-precache, so that it can be used offline. If I'm connected to the network, everything works fine. When I go offline, the requests for html resources (that are in the template cache) fail because it seems it is requesting the path from the network.
Is there something I need to add to my sw-precache config in order to have it defer to angular to handle retrieval of html files?
ok, so this is how I solved this. I am using Angular JS 1.6.4 with sw-precache.
I have CacheStorage via service workers, so using service workers I know I am expecting devices to support certain functionality, in my case we know our users will have Android Tablets with Chrome and support is valid.
I am developing a progressive web app with offline functionality.
So, the theory...I have directives which have templateUrls.
Using this post: https://thinkster.io/templatecache-tutorial
I basically have my directive code:
angular.module('app').directive('location',
['$timeout', 'notify.service', 'user.settings.service', 'log.service',
function ($timeout, notify, userSettings, log) {
return {
restrict: 'EA',
... controller etc..,
templateUrl: '/App/core/directives/location.html'
}
}
]);
Now, when this app goes offline, the cached instances of the content was not kicking it - annoying.
So, after much procrastinating I got down and dirty.
My solutio is, keep the templateUrl as it is, but overwrite the content via the $templateCache service.
To do this, you append a RUN function with your directive (for clarity). We know the service worker cache representation of our Url files contains the common path, in my case: '/App/core/directives/location.html'.
So, using new technology in the browser, window.caches gives me access to the CacheStorage that the service workers uses, I can then use the API available: https://developer.mozilla.org/en-US/docs/Web/API/Cache
I can then use the match method to find the matching service worker cache content, read that stream of binary and convert to HTML and then tell $templateCache to replace it with the service worker cached value.
So, for completeness (and you can create a common service which replaces the cached values based on templateUrl - which I will be doing for each directive)
(function () {
'use strict';
var templateUrl = '/App/core/directives/location.html';
// <location on-location='someFunc'></location>
// provides a form/control to find a location either by GEO location or manual city search
angular.module('app')
.run(['$templateCache', function ($templateCache) {
var cache = window.caches;
cache.match(templateUrl, { ignoreSearch: true }).then(function (response) {
if (response) {
response.body.getReader().read().then(function (cachedResponse) {
// convert the Uint8Array value to HTML string
var content = new TextDecoder('utf-8').decode(cachedResponse.value);
$templateCache.put(templateUrl, content);
//console.log($templateCache.get(templateUrl)); // debug
});
}
});
}])
.directive('location',
['$timeout', 'notify.service', 'user.settings.service', 'log.service',
function ($timeout, notify, userSettings, log) {
return {
restrict: 'EA',
... controller, scope etc...
templateUrl: templateUrl
}
}
]);
})();
Draw backs...the RUN process is synchronous, so initially they have to hit the site online first...but thats how service worker needs to work anyway, so thats handled in training :)
I expect there to be a better option, but for the time being thats the solution I have, I will be creating a template service for replacing $templateCache values based on the var templateUrl each directive will have, so the code becomes cleaner in each directtive....i considered having a global arr of templates and files, but, just a bit obscure, think its cleaner for each directive
my original solution was not 100%
To solve this, use sw-precache and sw-toolbox
Using a gulp configuration you can setup sw-precache to cache you content and extend this with sw-toolbox to use cached responses based upon routing configuration
see: https://developers.google.com/web/ilt/pwa/using-sw-precache-and-sw-toolbox
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.
Is it a good practice to call services directly from a Angular JS Directive?
Here is an example: directive to take name as input and calls a service(connects to db) to get the HTML content and render it.
a service call is made inside the linkFn to get the HTML content
or
return {
restrict:'EA',
scope:{
name:"=",
getPartial : "&"
},
link:linkFn
}
here getHTMLContent is implemented in the controller and calls the same service.
No. Imagine if you put that directive in an "ng-repeat". You'd have way too many calls to the server. How you retrieve your model should be separate from the way you present the model.
Little brief: I'm using AngularJs with Meteor+Blade without using Meteor_angularjs package for meteor. Blade constructs the body of the page in the server then I manually bootstrap angular in the client.
Blade has template files available under Template['template_name'] so they can be easily rendered on the client. I would like to do something like:
div(ng-include='content.blade')
// HTML => <div ng-include='content.blade'></div>
and somehow make it work.
To keep compatibility and not creating new directives I thought it could be possible to intercept the XHR requests angular makes to static templates and add the condition
if(URI ends with '.blade') then
name <- strip '.blade' in URI
return Template[name]()
Which should return the compiled HTML for that template.
UPDATE:
Coincidentally I ran into $templateCache and now I think it's the way to go.
I created a 'ngMeteor' module that I'll use for meteor-angular integration.
angular.module 'ngMeteor',[], ->
throw 'Meteor object undefined.' unless Meteor? # Is it fine to put here?
angular.module('ngMeteor.blade',['ngMeteor']).
run ($templateCache) ->
$templateCache.put "#{name}.blade", render() for own name, render of Template
In my app:
angular.element(document).ready ->
angular.bootstrap document, ['app']
app = angular.module 'app', ['ngMeteor.blade'], ->
app.controller 'mainCtrl', ($scope,$templateCache) ->
$scope.content = $templateCache.get "content.blade" # Works!!
Blade(body.blade):
#main(ng-controller='mainCtrl') {{ content }}
Now it works, I can get the rendered template from the controller after injecting $templateCache and geting the template by its name but ng-include still won't work.
My previous update in the question was actually the correct answer, ngInclude didn't work for me because of div(ng-include="'content.blade'") ... yes, the inner quotes! its like the Nth time I have that problem.
In resume the answer is:
angular.module('blade').
run ($templateCache) ->
$templateCache.put "#{name}.blade", render() for own name, render of Template
Template is the meteor global variable where blade will store templates ready to be rendered, then with $templateCache I put the rendered templates with the corresponding names/ids, that way Angular can use them.
EDIT: Based on this question I created a meteor package ng-meteor for braceless angular development in meteor.