Angular - Page does not bind variable outside view when specific view url is requested - angularjs

I tried to solve the problem but could not find the solution for this one. I have 2 views home and cart. Home displays all the products and cart displays all the items added to the cart. Backend for this is NodeJS which just servers index file and processes views.
In the following index file, I have {{fullCart.totalItems}} . When I try localhost:3000 then it binds perfectly by showing 0 and routes to localhost:3000/home but when I try localhost:3000/home url directly in the browser then it does not bind {{fullCart.totalItems}} so nothing is displayed
index.html
<body ng-app="bagitApp" ng-init="quanArr=[1,2,3,4,5,6,7,8,9,10]">
<div class="container-fluid nav-color navbar-fixed-top" ng-controller="headerController">
<div class="container">
<a class="navbar-brand" href="#"><img class="img-responsive" src="images/logo.png"></a>
<nav>
<div class="navbar-header">
<button type="button" class="navbar-toggle nav-btn" data-toggle="collapse" data-target="#navBar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="collapse navbar-collapse" id="navBar">
<ul class="nav navbar-nav">
<li>Home</li>
<li>Cart</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><i class="glyphicon glyphicon-shopping-cart"></i><i class=" teal new badge">{{fullCart.totalItems}}</i></li>
</ul>
</div>
</nav>
</div>
</div>
<div class="container pan-mar" ng-view>
</div>
</body>
main.controller.js
var app=angular.module('bagitApp',['ngRoute']);
app.config(['$routeProvider','$locationProvider',function($routeProvider,$locationProvider){
$routeProvider
.when('/home',{
templateUrl:'partials/Products Panel.html',
controller:'productsController'
})
.when('/cart',{
templateUrl:'partials/cart.html',
controller:'cartController'
})
.otherwise({
redirectTo:'/home'
});
$locationProvider.html5Mode({enabled:true,requireBase:false});
}]);
app.factory('cartService',function(){
return {
cart:[],
totalItems:0
};
});
function headerController($rootScope,$scope,cartService){
$scope.fullCart = cartService;
console.log("headerController")
console.log($scope.fullCart)
}
function productsController($rootScope,$scope,cartService){
$scope.fullCart = cartService;
$scope.products = products;
console.log("productsController")
console.log($scope.fullCart)
$scope.addToCart=function(item,quantity){
$scope.fullCart.cart.push({item,quantity:parseInt(quantity)});
$scope.fullCart.totalItems += parseInt(quantity);
console.log($scope.fullCart);
}
$scope.removeFromCart=function(itemId){
}
}
app.controller('productsController',['$rootScope','$scope','cartService',productsController])
app.controller('headerController',['$rootScope','$scope','cartService',headerController])
Server.js
var express = require('express');
var server = express();
var engines = require('consolidate');
server.set('views',__dirname);
server.engine('html',engines.mustache);
server.set('view engine','html')
server.use(express.static(__dirname));
server.get('/:name',function(req,res){
res.render('index');
});
server.listen(3000,function(){
console.log("Listening on localhost:3000");
})

Your problem is that when you go to
localhost:3000
then on the server your express.static serves index.html as a static asset so it's not render using mustache.
Since mustache uses same syntax {{ }} as angular then when you go to /home route handler for /:name renders index.html using mustache and since you dont pass in any variable then mustache simply deletes this
{{fullCart.totalItems}}
what you should do is
1.create public folder and place all public assets in it and change
server.use(express.static(__dirname));
to
server.use('/public', express.static(__dirname));
-html templates into templates subfolder
-js files like angular.js into js subfolder, etc.
2.create views folder and place your index.html in it.
This way you avoid index.html is servered once as static and once render with mustache. from now on it's always rendered. Unfortunately this will lead to another problem which is mustache will overwrite or delete any {{}}
So one option is to change angular {{}} to something like [[ ]] by adding
appModule.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
});
Then you could use it in your template:
<div>[[message]]</div>
Or you can most probably change {{}} to something else in mustache too but i don't know myself but you can have a look at mustache docs

On the node service you will want to add this.
app.get('*', function(req, res, next){
res.sendFile(PATH_TO_INDEX);
});
This will respond with the index.html on any other route, and then once the angular app bootstraps it will take over on routing and render the correct page.
In your angular app you will want to add this as well for each script/css file.
<base href="/">
Make sure it is above any of your scripts or stylesheets though.

Related

AngularJS: Load page on link click

I got 2 divs, first has links pointing to individual pages and another one to display the content of pages the links are pointing to. Here is how it looks:
<div id="navigation">
<a href="http://mydomain/page1">
<a href="http://mydomain/page2">
<a href="http://mydomain/and-so-on">
</div>
<div id="content">
<!-- display content here -->
</div>
Is there a way to prevent redirecting the page on link click and display the content of the URL they point to? I'm doing it this way for SEO purposes so each individual pages can also be crawlable on their own.
I've heard of ng-include but I want to be sure I'm heading the right direction so I reckon I should ask first before going with it.
Thank you in advance.
Use AngularJS Routing for this purpose.
<a href="#page1">
<a href="#page2">
<a href="#and-so-on">
<div ng-view></div>
<script>
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("page1", {
templateUrl : "http://yourDomain/page1.html"
})
.when("/page2", {
templateUrl : "http://yourDomain/page2.html"
})
.when("/and-so-on", {
templateUrl : "http://yourDomain/and-so-on.html"
});
});
</script>
Note: Must include angular-route.js

use ngStorage values in the template of site

I've got a site that uses ngStorage to save cart data until checkout, when it is then stored in the database. When using vm.$storage = $localStorage; in my controller, I can access the cart information easily for the part of the page in the section of index.html but I WANT to be able to access and display information from ngStorage in the header of my site, which is nested inside .
I've tried adding ng-controller="SiteController" to my li tag but still don't get anything to display that way.
How can I get the localStorage using ngStorage to display in the template (index.html) of my site?
My index.html file is setup something like this:
<html ng-app="myApp">
<body>
// a bunch of code to show my other navigation
// code to show my shopping cart at a glance
<li class="quick-cart">
<a href="#">
<span class="badge badge-aqua btn-xs badge-corner">
{{vm.$storage.cart.items.length}}
</span>
<i class="fa fa-shopping-cart"></i>
</a>
<div class="quick-cart-box">
<h4>Shop Cart</h4>
<div class="quick-cart-wrapper">
<a href="#"><!-- cart item -->
<h6>Item Name</h6>
<small>$12.34</small>
</a><!-- /cart item -->
<!-- cart no items example -->
<!--<a class="text-center" href="#"><h6>0 ITEMS ON YOUR CART</h6></a>-->
</div>
<!-- quick cart footer -->
<div class="quick-cart-footer clearfix">
VIEW CART
<span class="pull-left"><strong>TOTAL:</strong> $54.39</span>
</div>
<!-- /quick cart footer -->
</div>
</li>
//other code between the header and controller content
<div ng-view></div> //the CONTENT section controlled by each controller
//other code to finish the page
My site-controller.js code is:
/* global angular */ angular.module('myApp')
.controller('SiteController', SiteController);
function SiteController($route, $routeParams, AuthFactory, jwtHelper, $window, $localStorage, $sessionStorage) {
var vm = this;
vm.$storage = $localStorage;
vm.$storage.cart = vm.$storage.cart;
console.log(vm.$storage.cart);
}
Since you are using controllerAs syntax in controller you need to use the as alias in ng-controller
ng-controller="SiteController as vm"
This defines the vm you are already using in the view for:
{{vm.$storage.cart.items.length}}

HTML anchor conflicts with express router

I'd like to use the bootstrap tab-list in my project. While it contains anchors point to the sub-panel of the list. These anchors became invalid when I set the express router. The HTML code is like:
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a class="allerta" style="font-size:15px;"
href="/#overview" aria-controls="overview" role="tab" data-toggle="tab">Overview</a></li>
<ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active allerta" id="overview" style="
margin-top:15px;margin-bottom:15px;font-size:18px">
...
</div>
</div>
This href="/#overview" didn't point to the tabpanel anymore after I set up the express router. Instead it points to a empty page which url is "localhost:3000/#/overview". While if I delete the "/" before overview. It will conflict with the $routeProvider in Angularjs. The js file was as below:
var express = require('express');
var app = express();
app.use(express.static(__dirname));
app.listen(3000);

Angular JS for creating a master page child page effect

I need this Master Page and Child Page functionality in my application that uses HTML and calls Web Apis using AngularJS.
I'm having a problem in routing in this scenario.
Code used for Routing in Route.js:
var MainApp = angular.module('MainApp', ['ngRoute']);
MainApp.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: '../partials/DashboardMenu.html',
controller: 'DashboardMain'
})
.when('/Holidays', {
templateUrl: '../partials/Holidays.html',
controller: 'Holidays'
})
.when('/Projects', {
templateUrl: '../partials/Projects.html',
controller: 'Projects'
})
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
});
Dashboard.html
<body ng-app="MainApp" ng-controller="DashboardMainController">
<div class="view-animate-container">
<div ng-view class="view-animate"></div>
</div>
DashboardMenu.html
<div class="container-fluid btn-group">
<div class="row">
<a href="../partials/MyProfile.html" class="thumbnail">
<img src="" alt="My Profile" />
</a>
<a href="../partials/Projects.html" class="thumbnail">
<img src="" alt="Projects List" />
</a>
<a href="../partials/Holidays.html" class="thumbnail">
<img src="" alt="Holidays List" />
</a>
</div>
Below is the folder structure in my application:
After the User logs in from the Login Page, the user should be redirected to Dashboard.html with the default child view as DashboardMenu.html
In login Service.cs, when I authenticate the User and try to redirect him to the Dashboard.html with the below code snippet, it's just appending the URL with the Dashboard.html.
$location.path('DashboardMenu.html')
For this, I've added <base href="/" /> in Dashboard.html and locationProvider.html5mode and hasprefix but nothing worked for me. Please let me know where I'm missing..
It sounds like you are trying to implement some kind of version of nested views with ngRoute, which does not support that. I would suggest using ui-router which has support for nested states.
$location.path() should be set to url value that matches in your routing config.....not to the template path
Try changing
$location.path('DashboardMenu.html')
to
$location.path('/')
Same with your href values.... should be url not template
Chnge
<a href="../partials/Projects.html" class="thumbnail">
to
<a href="/Projects" class="thumbnail">
NOTE: Make sure server is configured for using html5Mode
You also need to remove ng-controller from templates that are used by routing that have controller declared already in the routing config. Otherwise you will end up with 2 instances of the controller running
Might suggest you study some more tutorials

How to prevent services from firing before user is authorized in AngularJS app

I have a service that is called to get the authorized user's location list. This information is used to populate a select list and they can switch locations to view different information.
The code for the select list is in the nav bar in the index.html but I don't want the service to fire on the page until after they user has been successfully authenticated and the app switches to the main view.
I'm using ng-show to hide the navigation bar with an isAuthorized() function for the AuthCtrl. However, the service call from the LocationCtrl to populate the ng-repeat always fires whether the user is logged in or not. I could move the nav component into the main view but then I'd need to have it in all the views that are protected. What is the best way to handle populating service-based menu items in a single page app?
index.html
<!doctype html>
<html lang="en" ng-app="betterbooks">
<head>
scripts...
</head>
<body>
<nav class="navbar-fixed-top" ng-controller="AuthCtrl as auth">
<div class="container" ng-show="auth.isAuthorized()">
<ul class="navbar-right">
<li>Home</li>
<li class="dropdown">
Accounts <span class="caret"></span>
<ul class="dropdown-menu" ng-controller="LocationCtrl">
<li ng-repeat="location in locations">
<a href="#/location/{{ location.id }}/">
{{ location.name }}
</a>
</li>
</ul>
</li>
<li><button ng-click="auth.logout()">Logout</button></li>
</ul>
</div>
</nav>
<div class="view-container" style="height:100%">
<div ui-view class="view-frame"></div>
</div>
</body>
</html>
Use an ng-if instead. The navbar won't be loaded into the dom until auth.isAuthorized() is true, so the LocationCtrl won't render or run until that point.

Resources