I am trying to create a nice dynamic theming system in my angular app.
Basically I have a Wordpress plugin which you pick via a dropdown which theme you want for my Angular app (which is on the same server in a subfolder), and I pass along the theme via a GET param, www.mywebsite.com/myapp/welcome?theme=white_theme, and the angular app in that folder currently will quickly set in the frontcontroller (think I will move this into an app.js resolve for the route so it happens before the controller, right now I just have the resolve setting a default theme):
var dynamic_theme = URI.parseQuery(query_string).theme; //url param gotten via URI js library
if(dynamic_theme) {
$rootScope.theme_name = dynamic_theme;
} else {
$rootScope.theme_name = 'default';
}
and later on in the index.html i include the dynamic theme via ng-href:
<!-- build:css(.tmp) styles/generic.css -->
<link rel="stylesheet" href="styles/generic.css">
<!-- endbuild -->
<link rel="stylesheet" ng-if="theme_name" ng-href="styles/themes/{{theme_name}}/main-theme.css">
But I also want the .html templates themselves to be able to be overwritten by our design theme for each theme.
For example, in app.js, to start off this 'questionnaire' app I have this defined:
templateUrl: 'views/main.html',
and in that file, i have a directive:
That directive uses the template 'views/question.html'
which inside of that file I decide whether to get 'views/templates/radio.tpl.html', 'views/templates/checkbox.tpl.html', 'views/templates/dropdown.tpl.html' based on the question-type passed to the directive.
like so:
<div ng-include src="'views/templates/' + currentquestion.question_type + '.tpl.html'"></div>
I guess maybe I can pass the theme into the directive (or just have access to the $rootScope) and do something like so:
<div ng-include src="'views/templates/' + dynamic_theme + '/' + currentquestion.question_type + '.tpl.html'"></div>
I was just curious if that sounds like a plan. or is there a better way to do this (or even a real theming resolver library/setup you can use for Angular that does the same things that I'm trying to achieve manually).
There seem to be a number of different ways to do this, the most promising looks to be using templateUrl as a function:
templateUrl: function(elem,attrs){
return 'views/templates/' + resolveTheme() + 'main.tpl.html';
},
You would have to write resolveTheme() yourself, possibly as a global or a service.
Alternative
Another option, if you can precompile your templates you can use the $templateCache and dynamically load the right template pack. You'd need to make sure this happened before any of the templates were requested as angular will make an HTTP request for any templates that it can't already find.
Here is one way to pre-compile your templates:
https://github.com/karlgoldstein/grunt-html2js
You could then have multiple template packs: template-theme1.js, template-theme2.js
And either build multiple versions of the app or include these templates after your application code (but before any templates get requested).
Related
I would like to preload templates in AngularJS (with ng-route) so that when I am on the home page, after loading all the necessaries element, I can download some sub-pages of my application in order to, if the user lost connexion, he is still able to go on that page, without an internet connexion.
I tried to make different asynchronous calls on my pages but I'm not getting anywhere.
I hope it's clear
There are two approaches for this:
The first one is to use an Ajax call and get the HTML for your Sites and load it into the template Cache by yourself:
$http.get('./template.en.html').then(function (result) {
//put template into cache
$templateCache.put('myTemplateName', result.data);
});
The second would be to use OcLazyLoad:
$ocLazyLoad.load([
'path/to/template.html'
]);
But with this approach your Template files need to look like this:
<script type="text/ng-template" id="myTemplateName">
Content of the template.
</script>
Also you could load your controller files with ocLazyLoad
I'am using node.js with sails.js for backend and angular.js for frontend.
In angular i am using one main controller and some childs conrtoller.
As you know, by default in sails.js, in file layout.ejs included all java scripts and css files between tags
<!--SCRIPTS--><!--SCRIPTS END-->
and
<!--STYLES--><!--STYLES END-->
Main content are included to <%- body %> tag
When i am lifted sails, go to browser and inspect "elements" i see some problem:
main controller (let it be "myApp") in angular generating html by using layout.ejs like main body (with all css and js), and then included controllers content.
Now problem:
Problem is that another child controllers of "myApp" generating by using layout.ejs too. And thats why some scripts included multiple times.
Example: 4 child controllers = 4 included of google.maps.api. Thats bad!! code so dirty!
And now question: how i can fix this issue, and make scripts and css included just one time?
Create another layout let's call it views/blanklayout.ejs with just this content:
<%- body %>
Now, use this layout with all child controller views.
Do either
In your sails controller set layout to blanklayout: res.locals.layout = 'blanklayout';
OR you can also specify layout in routes e.g.
'GET /test': {
controller: 'TestController',
action: 'test',
locals: {
layout: 'blanklayout',
},
},
PS: You can swap layouts also, meaning have just <%- body %> in layout.ejs and another layout (e.g. mainLayout.ejs to contain present content of layout.ejs. That way you'll not have to specify to use mainLayout only for main controller view.
I have an app where the entire routing is handled by the angular app. For instance I have many angular routes such as the following:
$routeProvider
.when("/users",{ controller: "userController", templateUrl: "partials/users.html" })
and on the back end app I have
router.get('/partials/:name', function(req, res, next) {
var name = req.params.name;
res.render('admin/partials/' + name);
});
This set-up also uses the ugly localhost/#/ hack. I want to switch all routing to Express and get rid of this hack in the process. What options do I have, in terms of least amount of files that will need to be modified.
Basically I want to return full rendered HTML with dynamic data generated from API routes for that particular endpoint integrated with it (possibly with the use of an HTML preprocessor such as Jade), and stop using Angular's to render templates and then embed API data to it.
What options do I have, in terms of least amount of files that will need to be modified.
is hard to decide without knowing your code and it's dependencies.
But I would suggest to have a closer look at jade conditionals, jade includes and jade extends. I use the jade preprocessor from within express apps to prepare jade templates and are very satisfied with that solution.
If you generate HTML-pages without any further dynamic content consider to use express' static feature.
If you have to do some very special processing of jades output you can do it within the callback before storing/delivering the file.
A snipped:
jade.compile('./templates/jade/remotecontrol.jade',
{title:'Remotecontrol',
copt:customoptions,
key:project.key,
objects:JSON.stringify(project.objects),
buttons:{login:true},
controls:{joystick:true},
forms:{login:true}},
{callback:storeTo,
storeTo:__dirname+'/projects/'+project.key+'/stk/index.html',
pretty:true})
For a template like (please recognize the "include ../../../" as the path has to be relative from the template, not the node app)
doctype html
html(lang="de")
head
title #{title}
meta(charset="UTF-8")
include ../../../templates/jade/favicon.jade
meta(name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no")
link(rel="stylesheet" type="text/css" href="styles/client.css")
script.
var objectsToInject=!{objects};
var key='#{key}';
...
body
include ../../../templates/jade/loading.jade
div.bodycontainer()
button.beforebgr(name="fullscreen" id="fullscreen" class="fullscreen") Fullscreen
if controls.joystick
div.draggable(id="divjoystick" class="draggable ui-widget-content")
include ../../../templates/jade/joystickbase-svg.jade
include ../../../templates/jade/joystick-svg.jade
...
- var scriptname="'libs/js/remotecontrol.js'"
include ../../../templates/jade/loadscript.jade
I've learning this new tool since some days ago and know I'm beggining to have my own doubts.
I have an index.html, which holds almost all my app like so:
<html>
<head>
.
.
.
<body>
<div ng-include="'header.html'"></div>
<div ui-view></div>
.
<!-- Loads all the scripts and other stuff-->
</body>
Ok, in the website I'm building, I have some sections that share the header, that's why I include it. Nonetheless, there is another section where is completely different from the others, hence, I don't need to include the header.
Now, the question is: How can I route to this completely new section ? Because the index loads the other views in the below the header. All I can think about right now is creating another index.html-like page, loading all the scripts and everything again. I think there should be a more elegant solution in Angular.
I'm using angular-ui-router for the routing.
Can you please give me a hand? Thanks
Use nested states, put this in your app's state configuration.
$stateProvider.
$state('stateWithHeader', {
template: '<header></header><div ui-view></div>',
controller: 'HeaderStateController'
}
.$state('stateWithHeader.subState', {
template: '<div>Content!</div>',
controller: 'HaderSubStateController'
}
.$state('stateWithoutHeader', {
template: '<div>Yeah, no header!</div>',
controller: 'HeaderStateController'
};
Make sure to read the docs, they're super informative and clear on most subjects.
What #Claies said above will absolutely work. Here's an example from my own site at http://PaperQuik.com.
I have multiple routes which correspond to different templates. Each one just does the following to get the same menu header at the top of the page:
<div ng-include="'views/menu.html'"></div>
If I needed a different top I could use a different include. You can see the source to my various templates here: https://github.com/JohnMunsch/PaperQuik/tree/master/app/views
Note: My example is just using the old ngRouter (not the new one which is expected for AngularJS 1.4) and thus it is way less sophisticated than what you can do with either the new ngRouter or the AngularUI Router you're using. Still, you can see how easy it is even with that super simple router.
I'm trying to use the RouteProvider functionality in Angular. A different partial html template should be loaded depending on whether the user is editing a form, viewing a list of completed entries, etc. I've been unable to load the html templates within the same page. Instead, the user is redirected to a different page.
Here's the relevant Angular code:
.when(/new', {
controller: 'CreateCtrl'
templateUrl: 'partials/newform.html'
The Laravel Route:
Route::resource('services', 'ServicesController');
The newform.html file is located at resources/views/partials/newform.html within Laravel.
Any thoughts on how I can load these partial html templates from Laravel?
One way would be to reference the full path to the partials
.when('/new', {
controller: 'CreateCtrl'
//depending on your path adjust it
templateUrl: 'partials/newform'
since you are just using .html not tempalte.blade.php file for template you should move it to public folder.
Update:
If you really dont want to move the template out of view folder of laravel
create a route and serve your html from there
Route::group(array('prefix' => 'partials'), function(){
Route::get('/newform', function()
{
return File::get(app_path().'Views/partials/angular.html');
});
});
Note: I will suggest you not to mix Laravelc template with Angular, keep Laravel as REST API, and your Angular should separate layer.
Here are some Pros and Cons for both approach
I found another way using gulp, i leave my solution :)
In gulpfile.js inside elixir function add this line:
var elixir = require('laravel-elixir');
elixir(function(mix) {
mix.copy('resources/assets/js/angular/components/**/*.template.html', public/angular-templates');
//Find all files with suffix .template.html
});
As you notice it, i created a folder called 'angular' and then another one called 'components', there we will have our components
Angular-----------------------------
--Components------------------------
----my-component.directive.js-------
----my-component.template.html------
We have to create a global angular variable taking our browser window origin (www.myapp.com, localhost:8000, etc) by doing:
angular.module('myModule',[])
.value('pathAssets', location.origin + '/angular-templates/')
In our templateUrl we will call the template by writting:
templateUrl: pathAssets + '../angular-templates/my-template.html',
I have to say we have to concat our angular files in a file, otherwise it won't work D: if you don't know how to do it, add these lines in your gulpfile.js
mix.scripts([
'../../../bower_components/angular/angular.min.js',
'angular/app.js',
'angular/controllers/**/*.controller.js',
'angular/components/**/*.directive.js',
'angular/bootstrap.js',
], 'public/js/app.js'); //We concatenate angular files saving them in app.js
Finally execute the command 'gulp' in terminal(In our project), it should generate a new folder in public called angular-templates.
CONCLUSION
1. Move all your angular templates to public inside a specific folder by using elixir.
2. create a global variable in angular to save your origin URL and use it in your directives it automatically with this template in public.