Dealing with Django translation inside AngularJS partials (ng-view) - angularjs

I'm having problems with the translation service provided by Django inside AngularJS partials. It seems Django is translating the content inside a partial only the first time my website is loaded. As of now I'm providing index.html with Django and then loading each view with ng-view directive. I got django and angular routing working nicely.
Inside my Django templates folder I have
this structure. Each of these files is just a regular html template with some content being translated by Django.
My django urls.py:
urlpatterns += i18n_patterns(
url(r'^$', views.homepage, name='index'),
url(r'^views/page-home.html/$', views.homeView),
url(r'^views/(?P<page>[-\w]+.html)/$', views.angularViews),
url(r'^(?P<path>.*)/$', views.angularRedirector),
)
And inside my angular app.js:
$routeProvider
// Load home by default
.when('/', {
templateUrl: 'views/page-home.html',
controller: 'homeController'
})
// home page
.when('/home', {
templateUrl: 'views/page-home.html',
controller: 'homeController'
})
// contact page
.when('/contact', {
templateUrl: 'views/page-contact.html',
controller: 'contactController'
})
// otherwise
.otherwise({
redirectTo: '/'
});
My index.html structure looks like this:
<!-- index.html -->
{% load static %}
{% load i18n %}
<!DOCTYPE html>
<html>
<head>
<!-- Head stuff [...] -->
</head>
<body ng-app="app" ng-controller="controller">
<!-- some content -->
<h1>{% trans "Hello world" %}</h1>
<!-- Views are injected here -->
<div class="page {$ pageClass $}" ng-view></div>
</body>
</html>
And one of the templates, for example page-home.html looks like this:
<!-- page-home.html -->
{% load static %}
{% load i18n %}
<!-- more content -->
<h2>{% trans "Goodbye World" %}</h2>
I'm currently working with 3 languages (English, Spanish and Deutsche). If I load localhost:8000, Django will automatically redirect to localhost:8000/es/#/, since Spanish is my default browser language. All content will render nicely, so DOM looks like this:
<!-- [...] -->
<body ng-app="app" ng-controller="controller">
<!-- some content -->
<h1>Hola mundo</h1>
<!-- Views are injected here -->
<div class="page page-home" ng-view>
<!-- more content -->
<h2>Adiós mundo</h2>
</div>
</body>
<!-- [...] -->
Here is where things get tricky. If i go to localhost:8000/de/#/ or localhost:8000/en/#/, just the content directly inside index.html will be translated to the current language, while the content inside ng-view will remain the same. So if I change to Deutsche my DOM will render like this:
<!-- [...] -->
<body ng-app="app" ng-controller="controller">
<!-- some content -->
<h1>Hallo welt</h1>
<!-- Views are injected here -->
<div class="page page-home" ng-view>
<!-- more content -->
<h2>Adiós mundo</h2>
</div>
</body>
<!-- [...] -->
Guess what, if I change the browser language to Deutsche, then all the content will render to Deutsche but if I visit localhost:8000/en/#/ or localhost:8000/es/#/, only the content outside ng-view will change. I don't understand what is happening here. How do I get the language to change inside the ng-view according to the url language, not the browser language?

Ok, I got it working. It turns out Angular will set the Accept-Language header only once, so the content inside ng-view would only translate once considering the browser's language.
So in my app.js configuration I had to store the language from the url and set the Accept-Language header on every request:
app.config(["$httpProvider", function($httpProvider) {
var language = window.location.pathname.split('/')[1];
$httpProvider.defaults.headers.common["Accept-Language"] = language;
}]);
That solved my problem.

Related

reload directives on change page angular

I write some code in angular but I have a problem with the reload of my directives when I change the page. So, the files that are included on all my pages not reload when I go in a page from menu.
This is some code in a app.js file:
$stateProvider
.state('dashboard', {
url:'/dashboard',
templateUrl: 'views/dashboard/main.html',
resolve: {
loadMyDirectives:function($ocLazyLoad){
return $ocLazyLoad.load(
{
name:'sbAdminApp',
files:[
'scripts/directives/header/header.js',
'scripts/directives/header/header-notification/header-notification.js',
'scripts/directives/sidebar/sidebar.js',
'scripts/directives/sidebar/sidebar-search/sidebar-search.js'
]
})
And some code from a controller of a page:
"use strict";
angular
.module("sbAdminApp",['ngRoute'])
.controller("ServicesCtrl",function($scope,getasap,NgTableParams,ngDialog){
})
If you are trying to use a header across all your views, you shouldn't put it in your lazy load. Your index.html should look like this:
<body ng-app="app" ng-controller="AppCtrl as appCtrl">
<!-- Navigation -->
<div header></div>
<!-- /.navbar-top-links -->
<!-- Page Content -->
<div id="page-wrapper" ui-view></div>
<!-- /#page-wrapper -->
</body>

Load only body on page change

On my website i'm displaying the same header on each page and I wanted to know if there's an AngularJS / jQuery or simple JS solution to load only the content of the body and not the header on page change.
<html ng-app="headerApp" ng-controller="HeaderCtrl">
<head>
<!-- here I load my JS and css ... -->
<div ng-include="'templates/Header.tpl.html'"></div>
</head>
<body>
<div ng-include="'templates/IndexBody.tpl.html'"></div>
</body>
<footer><div ng-include="'templates/Footer.tpl.html'"></div> </footer>
</html>
So my HTML looks like this I have separate template for each parts. But for now I create a html file for each pages. So I think there's a way to change the ng-include in the body.
Thanks for your help !
This is kind of the idea behind single page applications. Angular provides a built-in router that does this for you, and there is also the popular ui-router plugin.
You would change your view to:
<html ng-app="headerApp">
<head ng-controller="HeaderCtrl">
<div ng-include="'templates/Header.tpl.html'"></div>
</head>
<body>
<div ng-view></div>
</body>
<footer><div ng-include="'templates/Footer.tpl.html'"></div> </footer>
</html>
and configure the router in app.js:
angular.module('headerApp', ['ngRoute']).config(function($routeProvider){
$routeProvider.when('/', {
templateUrl: 'templates/IndexBody.tpl.html',
controller: 'IndexBodyCtrl'
});
});
Note that you will need to include angular-route.js in your index.html. More reading here: https://docs.angularjs.org/api/ngRoute
If it's an Angular app would you not use ng-view? Everything outside the view is the template and static as such. If you aren't building a spa then Angular probably isn't the best approach.
If it's Jquery then you could just do:
$("article").load('templatefiletoload.html');
beware that loading in your content like this is poor from an SEO point of view. Use server side includes if possible

Angularjs: ngView not rendering view in jade

I'm new to angularjs and working on project where is need to use ngView with jade for rendering views. I have also searched through the previous questions asked about ngView here but couldn't find anything helpful. The issue I'm facing is whenever I use ngView as an attribute of div in jade it compiles the jade template and shows the compiled HTML like:-
<div ng-controller='ArticleListCtrl'>
<!-- ngView: -->
</div>
The jade template is:-
div(ng-controller='ArticleListCtrl')
div(ng-view)
The route using config function in my app.js is:-
var nodeApp = angular.module("nodeApp",["ngRoute"]);
nodeApp.config(['$locationProvider','$routeProvider',function($locationProvider,$routeProvider){
$routeProvider
.when('/',{
templateUrl: 'articles/art.html',
controller: 'ArticleListCtrl'
})
$locationProvider.html5Mode(true);
}]);
So, can anybody help me or point me in right direction if I'm doing something wrong?
This is the complete jade template:-
doctype html
html(ng-app='nodeApp' lang='en')
include ../includes/head
body
div(ng-controller='ArticleListCtrl')
div(ng-view)
And this is compiled html generated from the jade template above:-
<!DOCTYPE html>
<html class="ng-scope" lang="en" ng-app="nodeApp">
<head prefix="og: http://ogp.me/ns# nodejsexpressdemo: http://ogp.me/ns/apps/nodejsexpressdemo#"></head>
<body>
<div class="ng-scope" ng-controller="ArticleListCtrl">
<!-- ngView: -->
</div>
</body>
</html>

angularjs single page share the same DIV element

I try to implement a single page app with angularjs
There is the route code:
angular.module('todomvc', ['ngRoute'])
.config(function ($routeProvider) {
'use strict';
$routeProvider.when('/account', {
controller: 'TodoCtrl',
templateUrl: 'account.html'
}).when('/', {
controller: 'TodoCtrl',
templateUrl: 'todomvc-index.html'
}).otherwise({
redirectTo: '/'
});
});
The html of the single page is:
<!doctype html>
<html lang="en" data-framework="angularjs">
<head>
<link rel="stylesheet" ... >
<script ...></script>
</head>
<body ng-app="todomvc">
<ng-view />
<script type="text/ng-template" id="account.html">
a html template segment(*) here
///////////// this is the template of the first appearance. //////////////
</script>
<script type="text/ng-template" id="todomvc-index.html">
the same html template segment(*) here
///////////// this is the template of the second appearance. //////////////
But both appearance share a common template segment. How to remove the duplication?
</script>
</body>
</html>
By default, the second page is show up. After a user click a button on the second page, it will trigger $location.path("account"); and route to jump to the first page. In my case, both templates share a div block, that is, a common part is load to both templates. Currently, the template segment is copy and paste to both areas as shown in above code. But the copy-paste is hard to maintain. How can I share the template segment between the two text/ng-template?
Thank you.
Define your common div in a seperate .html file and include it using the ngInclude directive.
<ng-include src="commonDiv.html"/>
I strongly recommend a module called ui-route which provide a simple and easy way to maintain nested views and templates.

need advice on ng-view layout please

I am designing a page in angularjs that would be a mini SPA (single page app). This page is part of a larger web site that was written in traditional jquery and asp.net. The page will have 2 main sections - the 1st section is just some simple data elements that can be bound easily with ng-model's. The 2nd section will be dynamically generated based on user's interaction, and the data will be retrieved through ajax ($http or $resource).
So should I have ng-view on the whole content page that contains the 2 sections? Or should I only do ng-view on the 2nd dynamic sections? If it's better to have ng-view on the 2nd section only, how do I handle the routes in this case knowing that the 1st section's data should be preserved statically?
thanks.
You don't have to use ng-view and routes for your simple case (widget-like angular application inside other application). You can use ng-include instead. Here is an example of application. I prefer this approach because it does not require to use shared resource like URL location hash that may be already in a use by legacy application or other widgets. Application below switch views dynamically, loads different data for each view and affects it's display options (number of displayed items):
HTML
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script data-require="angular.js#*" data-semver="1.2.11" src="http://code.angularjs.org/1.2.11/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Here is my legacy app markup</h1>
<div ng-app="app" ng-controller="appController">
<div>
<input placeholder="Number of items" ng-model="numberOfItems"/><br/>
<select placeholder="View" ng-model="currentView" ng-options="view.name for view in views"></select>
</div>
<div ng-include="currentView.url"></div>
</div>
<div id="jqueryContainer">And here is some markup generated with jQuery<br /></div>
</body>
</html>
JavaScript
angular.module('app', []).
controller('appController', function($scope, $http) {
$scope.views = [{
name: 'view1',
url: 'view1.html',
dataUrl: 'data1.json'
}, {
name: 'view2',
url: 'view2.html',
dataUrl: 'data2.json'
}];
$scope.numberOfItems = 2;
$scope.currentView = $scope.views[0];
$scope.$watch('currentView', function(currentView) {
if(currentView && currentView.dataUrl) {
$http.get(currentView.dataUrl).success(function(data) {
$scope.data = data;
});
}
});
});
$(function(){
$('#jqueryContainer').append('<span>Some markup generated dynamically.</span>');
});
view1.html
<div>
<h2>View1 specific markup {{data.length}}</h2>
<ul>
<li ng-repeat="item in data | limitTo:numberOfItems">{{item.text}}</li>
</ul>
</div>
data1.json
[{"text":"Text1"},{"text":"Text2"},{"text":"Text3"},{"text":"Text4"},{"text":"Text5"}]
Plunker: http://plnkr.co/edit/Y5IZmPbrrO63YrL8uCkc?p=preview
You can also find useful examples of this approach in AngularJS documentation: http://docs.angularjs.org/api/ng.directive:ngInclude
yes you can separate the static view with the dynamic view, in actual this is what angularjs suggest.It is not required to move the scope of ng-app.
so you can do like this: menu is displayed as the static part
index.html
<body ng-app>
<ul class="menu">
<li>view1</li>
<li>view2</li>
</ul>
<div ng-view></div>
</body>
in your config file you can include your routing which page routes to which page and which controller to used on loading of any view.
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: 'MyCtrl1'});
$routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: 'MyCtrl2'});

Resources