AngularJS templating and making it faster? - javascript

I want to use AngularJS in combination with Django to make single-page application. In general, I have index page (search) and details page with more sub-pages.
And that makes a problem. I have one controller (for details and it is getting info about object which is chosen) and other controllers user that main controller using $controller function.
It looks like:
.controller('BuildingDetailsCtrl', ['$scope', '$routeParams', 'buildingsRepository', '$location',
function($scope, $routeParams, buildingsRepository, $location) {
$scope.details = null;
$scope.menu = templatesFolder + "buildings/menus/";
$scope.currentUrl = $location.url();
$scope.loading = true;
buildingsRepository.getDetails($routeParams.slug).then(function(res) {
$scope.details = res.data[0];
$scope.loading = false;
});
$scope.alert = {"type": null, "message": null};
}])
.controller('SecondCtrl', ['$scope', '$routeParams', 'buildingsRepository', '$location', '$controller',
function($scope, $routeParams, buildingsRepository, $location, $controller) {
$controller('BuildingDetailsCtrl', {$scope: $scope, $routeParams: $routeParams, buildingsRepository: buildingsRepository, $location: $location})
$scope.partial = templatesFolder + "buildings/details/info.html";
}])
and my urls:
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {templateUrl: templatesFolder + "buildings/index.html", controller: 'UserBuildingsCtrl'});
$routeProvider.when('/details/:slug', {templateUrl: templatesFolder + "buildings/details.html", controller: 'BuildingInfoCtrl'});
$routeProvider.when('/test/:slug', {templateUrl: templatesFolder + "buildings/details.html", controller: 'SecondCtrl'});
$routeProvider.when('/contact/:slug', {templateUrl: templatesFolder + "buildings/details.html", controller: 'BuildingContactCtrl'});
$routeProvider.otherwise({redirectTo: '/'});
}]);
On that details.htmlpage, I have one menu, but problem is loading, and everytime I change from, for example, InfoCtrl to SecondCtrl, my menu is being refreshed and I can see that (less than half second). It is irritating.
Is there any way to prevent loading of those templates, to load just partial, but with changing URL (I need it to be accessed from copied url etc)?

You can embed your template in the already-rendered page as a script of type text/ng-template:
<script type="text/ng-template" id="details.html">
<p>hello world</p>
</script>
Here is a plunk.
You should not need to call $controller() in your controller. You angular app will instance the controller needed by including a directive in your html like this:
<div ng-controller="BuildingDetailsCtrl">
...
</div>

Related

Dynamically changing routes using AngularJS

I have bunch of JSON models in my project and I need to show different models depends on user's actions.
Here is Angular router code:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeCtrl'
}).when('/doc/:section, {
templateUrl: 'views/doc.html',
controller: 'DocCtrl'
})
.otherwise({
redirectTo: '/'
});
}]);
And here is DocCtrl.js file:
app.controller('DocCtrl', ['$scope', '$http', 'JSONModelsService',
function ($scope, $http, JSONModelsService) {
var formData = {};
$scope.group = {};
$scope.sections = [];
JSONModelsService.get([section])
.then(function (response) {
console.log(response);
$scope.group = response.data.groups[0];
$scope.sections = $scope.group.sections;
});
}]);
I basically need to make section dynamic so I can show different models in my views. However, I'm confused how I can do it. I just have a folder called JSONModels with multiple json files.
If I understand your question correctly, you are aiming at replacing the [section] part of your code with an actual section identifier?
When a user visits your /doc/:section route, e.g. /doc/my-doc you can access the :section part by injecting the $routeParams service into your controller.
app.controller('DocCtrl', ['$scope', '$http', '$routeParams', 'JSONModelsService',
function ($scope, $http, $routeParams, JSONModelsService) {
...
Using the $routeParams service, you have access to your route parameters. So you can simple access the :section parameter, by reading it off $routeParams.section.
A full example (of what I think you're trying to achieve):
app.controller('DocCtrl', ['$scope', '$http', '$routeParams', 'JSONModelsService',
function ($scope, $http, $routeParams, JSONModelsService) {
var formData = {};
$scope.group = {};
$scope.sections = [];
JSONModelsService.get([$routeParams.section])
.then(function (response) {
console.log(response);
$scope.group = response.data.groups[0];
$scope.sections = $scope.group.sections;
});
}]);
If you would like to know more, take a look at step 7 of the angular tutorial: https://docs.angularjs.org/tutorial/step_07

How to redirect after login

I am trying to redirect a user to different page after user is authenticated. I am using jwt authentication and I tried with $location, $window for redirection but its throwing error $state.go is not a function. I am new to angular and I am guessing there should be way to redirect may using a service in angular but I am still new to factories and service.
I have my state provider like this in state.js file:
myApp.config(function ($stateProvider, $urlRouterProvider) {
// default route
$urlRouterProvider.otherwise("/Home");
var header = {
templateUrl: 'commonViews/Header.html',
controller: function ($scope) {
}
};
var footer = {
templateUrl: 'commonViews/Footer.html',
controller: function ($scope) {
}
};
// ui router states
$stateProvider
.state('Home', {
url: "/Home",
views: {
header: header,
content: {
templateUrl: 'views/HomePage.html',
controller: function ($scope) {
}
},
footer: footer
}
})
.state('LoggedIn', {
url: "/LoggedIn",
views: {
'header': header,
'content': {
templateUrl: 'views/LoggedIn.html',
controller: function () {
}
},
'footer': footer
}
});
});
and loginController.js:
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state)
{
$scope.email = "";
$scope.password = "";
$scope.token = "";
$scope.loginForm = function () {
var data = {email: $scope.email, password: $scope.password};
var url = 'rs/loginResource/login';
$http.post(url, data).then(function (response)
{
$localStorage.token = response.data.token;
console.log("Encoded Token in localstorage is:" + $localStorage.token);
if ($localStorage.token) {
// $location.url("/LoggedIn");
$state.go('/LoggedIn');
}
}, function (error)
{
console.log("error", error);
});
};
}]);
further I have to perform refresh token based on expiration time etc, so is it better to have separate the functions like using a service to do the signup and signin?
The problem is the definition of your controller and the way you're handling your injections. And no, referring to your own answer to your question, the problem is not the "order" of the injections. It's a bit worse.
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state)
in this code you're mapping '$scope' to a $scope variable, '$http' to $http, 'jwtHelper' to jwtHelper, '$localStorage' to $localStorage and '$state' to $sessionStorage, and you're not mapping anything to $state. So obviously you get an error when you try to call a method on an undefined $state variable.
So in short, you're injecting 5 dependencies and you're assigning 6 variables to your dependencies, which in turn results in things not doing what they're supposed to do.
You can use Angular $window:
$window.location.href = '/index.html';
$state. go accepts the view name, not the URL. Replace '/LoggedIn' with Logged and you should be good.
Use $state.go instead of $window and location.
Add $state injector on controller
write code $state.go('LoggedIn');
Instead $state.go('/LoggedIn');
Write state name('LoggedIn') instead of url('/LoggedIn').
Hopefully this will work in your case.
You need to add $window as a dependency to your controller if you are using $window,
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state','$window', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state,$window)
{
$window.location.href = '/index.html';
}
otherwise change the route like this, here also you need to inject $state,
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$state','$window','$state', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state,$window,$state)
{
$state.go('LoggedIn');
}

AngularJS controller called every time after ngRoute url is clicked

I have problem with below code. When I go to main controller url #/, Angular naturally calls main controller - it execute AJAX request. Problem is, that when I click #/some-url, and then #/ url again, this AJAX request is executed again, which is not desired and unnecessary due to performance. I thought controllers are called only once, but it doesn't look like this is the case, at least with ngRoute.
angular.module('robotsApp', ['ngRoute', 'controllers'])
.config(['$routeProvider', function($routeProvider){
var root = '/static/js/partials/';
$routeProvider.
when('/', {
templateUrl: root + 'main.html',
controller: 'main as main'
}).
when('/some-url', {
templateUrl: root + 'some_template.html',
controller: 'someController'
}).
otherwise({
redirectTo: '/'
});
}]);
angular.module('controllers', [])
.controller('main', ['$http', function($http){
$http.get('/user/recent-gain-loss').success(function(data){
this.recent_gain_loss = data;
}.bind(this));
}]);
<p>{{ main.recent_gain_loss }}</p>
Save the data in to a value and then check if the data are already set.
angular.module('values', [])
.value('recentGainLoss', {})
angular.module('controllers', ['values'])
.controller('main', ['$http', 'recentGainLoss', function($http, recentGainLoss){
if (Object.keys(recentGainLoss).length < 1) {
$http.get('/user/recent-gain-loss').success(function(data){
recentGainLoss = angular.extend(recentGainLoss, data);
});
}
this.recent_gain_loss = recentGainLoss;
}]);

$scope does not return any value

I am trying to access $scope variable inside my controller . when I console my $scope it shows number of values but when I try to access it via $scope. it return undefined.
I have attached screen shot of $scope
Here you can see it have $id, $parent , templateUrl but when i am trying to access it via $scope.id , $scope.parent , $scope.templateUrl it return undefined .
Edited :
I am trying to access template url . actually I want to attach some params with template url so that I can get them in my backend function
here is my code :
brainframeApp.config(
['$interpolateProvider', '$locationProvider', '$httpProvider', '$routeProvider',
function($interpolateProvider, $locationProvider, $httpProvider,
$routeProvider) {
//configuring angularjs symbos to not to conflict with Django template symbols
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
//$locationProvider.html5Mode(true).hashPrefix('!');
// setup CSRF support
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
console.log("TestDavy: App");
//The route provider
$routeProvider.
when('/', {
templateUrl: '/static/engine/partials/listbrainframes.html',
controller: 'brainframeCtrl'
}).
when('/brainframe/', {
templateUrl: '/views/post.html',
controller: 'brainframeCtrlx'
}).
when('/brainframe/:id', {
templateUrl: '/views/post.html',
controller: 'brainframeCtrlx'
}).
otherwise({
redirectTo: '/'
});
}]);
my controller :
brainframeAppControllers.controller('brainframeCtrlx',
['$scope', '$routeParams', function($scope, $routeParams) {
//console.log($scope.parent);
//$scope.templateUrl = 'views/post.html?id='+$routeParams.id;
//console.log($scope);
$scope.templateUrl = 'views/post.html?id='+$routeParams.id;
//console.log($scope.templateUrl);
}]);
When I put console.log on $scope, am able to see only these properties:
["$$childTail", "$$childHead", "$$nextSibling", "$$watchers", "$$listeners", "$$listenerCount", "$id", "$$ChildScope", "$parent", "$$prevSibling"]
If you want to access the template URL inside your controller:
brainframeApp.run(function($rootScope) {
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
$rootScope.templateUrl = next.$$route.templateUrl;
});
});
Now inside your controller, inject $rootScope and get the template URL
$rootScope.templateUrl

How does the "main" controller access $routeParams in this example?

I'm experimenting with $routeParams, by following along with this example in the AngularJS documentation. For reference, here is the script itself:
angular.module('ngRouteExample', ['ngRoute'])
.controller('MainController', function($scope, $route, $routeParams, $location) {
$scope.$route = $route;
$scope.$location = $location;
$scope.$routeParams = $routeParams;
})
.controller('BookController', function($scope, $routeParams) {
$scope.name = "BookController";
$scope.params = $routeParams;
})
.controller('ChapterController', function($scope, $routeParams) {
$scope.name = "ChapterController";
$scope.params = $routeParams;
})
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/Book/:bookId', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
// I will cause a 1 second delay
delay: function($q, $timeout) {
var delay = $q.defer();
$timeout(delay.resolve, 1000);
return delay.promise;
}
}
})
.when('/Book/:bookId/ch/:chapterId', {
templateUrl: 'chapter.html',
controller: 'ChapterController'
});
// configure html5 to get links working on jsfiddle
$locationProvider.html5Mode(true);
});
What I can't understand is this: how does MainController get the updated $routeParam object? I can see that as I click, items that MainController is responsible for setting are changing, but I don't understand how. It's making it a little tough to reproduce this behavior.
It doesn't get re-instantiated, and it's not "getting" the updated $routeParams object - the object in the controller is the routeParams object. It is the same object that is in the other controllers, not a "copy" of it.
So when the $routeParams object gets changed, the other controller already has the changes.

Categories

Resources