change page title in ui-router not work - angularjs

i try to change my page title in angular app use ui router
i found this demo and its work fine https://plnkr.co/edit/NpzQsxYGofswWQUBGthR?p=preview
but when i attempt to try the same demo not work i need to find issue that make my demo not work https://plnkr.co/edit/pqumJL?p=preview
why demo not change page title although it's work in demo

try this :
(function () {
'use strict';
angular
.module('app', ['ui.router'])
.config(config)
config.$inject = ['$stateProvider', '$urlRouterProvider', '$urlMatcherFactoryProvider'];
function config($stateProvider, $urlRouterProvider, $urlMatcherFactoryProvider) {
$urlRouterProvider.otherwise('/home');
$urlMatcherFactoryProvider.caseInsensitive(true);
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home.view.html',
data: {
pageTitle: 'Home'
}
})
.state('about', {
url: '/about',
templateUrl: 'about.view.html',
data: {
pageTitle: 'About'
}
})
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<script src="https://code.angularjs.org/1.3.3/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.11/angular-ui-router.min.js"></script>
<script src="app.js"></script>
<script src="app-directives/title-directive.js"></script>
<title>{{title}}</title>
</head>
<body>
<div class="panel" ui-view></div>
<ul class="nav navbar-nav">
<li>
<a ui-sref="home" ui-sref-active="activeState">Home</a>
</li>
<li>
<a ui-sref="about">About</a>
</li>
</ul>
</body>
</html>
https://plnkr.co/edit/JifcOKrUC9tBfV8jY5ko?p=preview

In plunkr you just have to replace
<script src="app-directives/title-directive.js"></script>
by
<script src="title-directive.js"></script>
I can provide you a better way to do so:
link: function (scope, element, attrs) {
var defaultTitle = element.text();
if (element[0].tagName === 'TITLE') {
var listener = function (event, toState) {
var title;
if (toState.data && toState.data.pageTitle) {
if(toState.data.placeholder && toState.data.placeholder.title)
title = toState.data.pageTitle, toState.data.placeholder.title;
else
title = toState.data.pageTitle;
} else if (defaultTitle) {
title = defaultTitle;
} else {
title = 'No title';
}
$timeout(function () {
element.text(title);
}, 0, false);
};
$rootScope.$on('$stateChangeSuccess', listener);
}
}

Thanks the problem solved
there is an error in ui router script and incompatible version
when use online version the problem solved
thanks all

Related

Make two layouts share the same $scope

I want to propose two layouts (ie, horizontal and vertical) for my contents. So switching in the selector will lead automatically to the corresponding layout. Here is the JSBin:
<html ng-app="flapperNews">
<head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.js"></script>
<script type="text/ng-template" id="horizontal.tpl">
<textarea ng-model="one"></textarea>, <textarea ng-model="two"></textarea>
<br><br>{{one}}+{{two}}
</script>
<script type="text/ng-template" id="vertical.tpl">
<textarea ng-model="one"></textarea><br><textarea ng-model="two"></textarea>
<br><br>{{one}}+{{two}}
</script>
<script>
var app = angular.module('flapperNews', ['ui.router']);
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('entry', {
url: '/',
params: { tpl: 'vertical' },
templateUrl: function (params) {
return params.tpl + ".tpl"
}
})
}]);
app.controller('MainCtrl', ['$scope', '$state', function ($scope, $state) {
$scope.one = "one";
$scope.two = "two";
$scope.layouts = ["horizontal", "vertical"];
$scope.$watch('layout', function () {
$state.go('entry', {tpl: $scope.layout});
})
}])
</script>
</head>
<body ng-controller="MainCtrl">
<select ng-model="layout" ng-init="layout = 'horizontal' || layouts[0].value" ng-options="x for x in layouts"></select>
<br><br>
<ui-view></ui-view>
</body>
</html>
However, with the above code, each time we change the view, $scope.one and $scope.two are reset to their initial values. I would hope the change in their textarea would remain regardless of the change of layout.
Does anyone know how to solve this?
Easy sharing same data between different views by using factories (AngularJS factory documentation). Try this example, it uses a simple factory named myFactory to share data between controllers. This also does work on the same controller as in your case.
var myApp = angular.module("myApp",[ "ui.router"]);
myApp.config(function ($stateProvider, $urlRouterProvider){
$stateProvider.state("state1", {
url: "#",
template: '<p>{{ aValue }}</p><button ng-click="bindValue(\'its me\')">Bind value</button>',
controller: "myController"
}).state("state2", {
url: "#",
template: '<p>{{ aValue }}</p><button ng-click="bindValue(\'its me\')">Bind value</button>',
controller: "myController"
});
});
myApp.controller( "myController", function($scope, myFactory) {
$scope.aValue = myFactory.myValue;
$scope.bindValue = function (value) {
$scope.aValue = value;
myFactory.myValue = value;
}
});
myApp.factory('myFactory', function () {
return {
myValue: ''
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
<div ng-app="myApp">
<nav>
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
</nav>
<div ui-view></div>
</div>
I think that you should use nested views - you can define main controller on parent route state and define two nested states corresponding to two views. This way parent controller will remain (it's not re-initialised when child states are switched) and only nested states views will be changed. Something like this:
$stateProvider
.state('myState', {
url: '/test/',
template: '<div ui-view></div>',
controller: function() {
//main controller shared by child states
...
}
})
.state('myState.view1', {
url: '/test/view1'
templateUrl: 'tpl-1.hmtl',
...
})
.state('myState.view2', {
url: '/test/view2'
templateUrl: 'tpl-2.hmtl',
...
})

Issue: $locationChangeStart is executing after page is redirected

$locationChangeStart is executing after page is redirected. So even i get error message page will be already redirected. How can i make page redirect after it executes $locationChangeStart.
Below is the index.html page from where i am linking to 'Home' and 'About' page.
<head>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="http://code.angularjs.org/1.2.13/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.min.js"></script>
<script src="index.js"></script>
<!--<script src="homecontroller.js"></script>-->
</head>
<body ng-app="routerApp" ng-controller="homeCntrl">
<form name="form.myForm">
<nav class="navbar navbar-inverse" role="navigation">
<ul class="nav navbar-nav">
<li><a ui-sref="home">Home</a></li>
<li><a ui-sref="about">About</a></li>
</ul>
</nav>
<div class="container">
<div ui-view></div>
</div>
</form>
</body>
Below is the index.js page where i have written code to display error message
var routerApp = angular.module('routerApp', ['ui.router']);
routerApp.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'home.html'
})
.state('about', {
url: '/about',
templateUrl: 'about.html'
})
});
routerApp.controller('homeCntrl', ['$scope', '$rootScope', function ($scope, $rootScope) {
$scope.$watch('form.myForm.$dirty', function (dirty) {
if (dirty) {
$rootScope.preventNavigation();
}
else {
$rootScope.allowNavigation();
}
});
$scope.form = {};
$scope.Save = function () {
alert('Save');
$scope.form.myForm.$setPristine();
}
}]);
routerApp.directive('confirmOnExit', function () {
return {
link: function ($scope, elem, attrs) {
window.onbeforeunload = function () {
if ($scope.form.myForm.$dirty) {
return "The form is dirty, do you want to stay on the page?";
}
}
$scope.$on('$locationChangeStart', function (event, next, current) {
if ($scope.form.myForm.$dirty) {
if (!confirm("The form is dirty, do you want to stay on the page?")) {
event.preventDefault();
}
}
});
}
};
});
Below is the home.html page
Name: <input name="input" ng-model="myModel.text">
<p>myModel.text = {{form.myModel.text}}</p>
<p>$pristine = {{form.myForm.$pristine}}</p>
<p>$dirty = {{form.myForm.$dirty}}</p>
<button type="submit" ng-click="Save()">Save</button>
So in the above example, Now i am in 'Home' page and i have filled the input field and now my page is dirty. Now when i click on 'About' first it will redirect to 'About' page and then it will execute $locationChangeStart and it will display error code.
How to make error message display first before page is redirected.
below is the plunker (Note: ui-sref is not working here, but exact code working fine in my VS. I am not able to figure out why. But my problem is how to check $locationChangeStart first and then redirect if it is not dirty)
https://plnkr.co/edit/LoGGusldqb74Zf5QGoOJ?p=preview

Routing is not working with Angular UI Router

I have following code to setup the routing using Angular UI Router:
index.html
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8" />
<title>AngularJS Routing</title>
<script src="js/angular.js"></script>
<script src="js/angular-ui-router.min.js"></script>
<base href="/" />
<script>
'use strict'
var myApp = angular.module('myApp', ['myApp.Controllers', 'ui.router']);
var myAppControllers = angular.module('myApp.Controllers', []);
myApp.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider.state('view1', {
url: '/view1',
controller: 'Controller1',
templateUrl: '/partials/view1.html'
}).state('view2', {
url: '/view2/:firstname/:lastname',
controller: 'Controller2',
resolve: {
names: function () {
return ['Misko', 'Voita', 'Brad'];
},
},
templateUrl: '/partials/view2.html'
});
$urlRouterProvider.otherwise('/view1');
$locationProvider.html5Mode(true);
});
myAppControllers.controller('Controller1', function ($scope, $location, $state) {
$scope.loadView2 = function () {
$state.go('view2', {
firstname: $scope.firstname,
lastname: $scope.lastname
});
}
});
myAppControllers.controller('Controller2', function ($scope, $stateParams, names) {
$scope.firstname = $stateParams.firstname;
$scope.lastname = $stateParams.lastname;
$scope.names = names;
});
</script>
</head>
<body>
<ul class="menu">
<li><a ui-sref="view1">View1</a></li>
<li><a ui-sref="view2">View2</a></li>
</ul>
</body>
</html>
I checked multiple times and I don't see any errors in console window of the chrome browser.
Can anyone help me to resolve this issue?
There's no ui-view directive in your html code. So the views have nowhere to render. You should add at least
<div ui-view></div>
to show the content of the views.

Can you use ng-click with ui-sref?

Can I do this?
<button ng-click='vm.foo()' ui-sref='state'>test</button>
Yes. ngClick will run, and then you'll transition to your state.
Demo (updated and working thanks to marioosh)
However, if you have an $event.preventDefault() in ngClick, it won't transition you to your state.
Full code example
<!DOCTYPE html>
<html ng-app='app'>
<head>
<script data-require="angular.js#1.4.3" data-semver="1.4.3" src="https://code.angularjs.org/1.4.3/angular.js"></script>
<script data-require="ui-router#*" data-semver="0.2.15" src="//rawgit.com/angular-ui/ui-router/0.2.15/release/angular-ui-router.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller='MainController as vm'>
<ul>
<li><a ui-sref='home'>home</a></li>
<li><a ui-sref='one' ng-click='vm.test()'>one</a></li>
<li><a ui-sref='two'>two</a></li>
</ul>
<div ui-view></div>
</body>
</html>
angular
.module('app', ['ui.router'])
.config(config)
.controller('MainController', MainController)
;
function config($locationProvider, $urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'home.html'
})
.state('one', {
url: '/one',
templateUrl: 'one.html'
})
.state('two', {
url: '/two',
templateUrl: 'two.html'
})
;
}
function MainController($scope) {
var vm = this;
vm.test = function() {
alert('test');
console.log('test');
}
}

Switching Angular view not updating variables

I'm just building out a simple app to learn AngularJS and having trouble updating variables when switching views. Here's what I have so far:
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainController',
controllerAs: 'main'
})
.state('team', {
url: '/team',
templateUrl: 'app/main/team.html',
controller: 'MainController',
controllerAs: 'main'
})
$urlRouterProvider.otherwise('/');
}
Here's part of my controller:
function MainController($timeout, webDevTec, toastr, $resource, $scope) {
var vm = this;
var GetTeam = $resource('https://apisite.com/api_endpoint/:teamId', {teamId: '#id'});
vm.teamName = '';
function getTeamInfo(id) {
var teamObj = GetTeam.get({teamId: id});
$timeout(function(){
vm.teamName = teamObj["name"];
},100)
};
vm.getTeamInfo = getTeamInfo;
}
Then in my main.html I call getTeamInfo with a ng-click:
<ul class="list-group">
<li class="list-group-item" ng-repeat="team in main.teams" ng-click="main.getTeamInfo(team.id)">{{ team.name }}</li>
</ul>
Clicking on that link will take you to team.html:
<div class="row">
<div class="col-sm-12">
<h3>{{ main.teamName }}</h3>
<ul class="list-group">
. . .
</ul>
</div>
</div>
For some reason "main.teamName" is not updating. I've tried the $scope.$apply(function(){vm.teamName = teamObj["name"]} approach as well with no luck. I also did 'console.log(teamObj["name"])' before vm.teamName and 'console.log(vm.teamName)' after to see if I get the expected results and I do. I just have no idea now why it's not updating the new view.
Thank you for your insight, patience, and time!
UPDATE 1
I also tried using $scope on my variables ($scope.teamName) and using $scope.$apply(function(){$scope.teamName = teamObj["name"]}) with no luck.
UPDATE 2
I also tried called $scope.$apply(); after 'vm.teamName = teamObj["name"]' with no luck
It looks like teamObj is not populated yet at the point when you assign vm.teamName
You would make your life so much easier if you just reference teamObj rather than creating a new property.
I made a plunker based on a modified version of your code to show a possible implementation. I couldn't get it to work using the controllerAs syntax and I'm not entirely sure why (possibly because of some issues related to sharing a controller; not sure). Anyway, hopefully it will be of some help to you.
DEMO
app.js
var app = angular.module('plunker', ['ui.router', 'ngResource']);
app.controller('MainController', MainController);
app.config(routeConfig);
function MainController($timeout, $scope, $resource) {
// mock data
var GetTeam = $resource('http://demo7592070.mockable.io/teams/:teamId', {teamId: '#id'});
//var GetTeam = $resource('https://apisite.com/api_endpoint/:teamId', {teamId: '#id'});
$scope.teamName = 'undefined';
$scope.getTeamInfo = getTeamInfo;
function getTeamInfo(id) {
var teamObj = GetTeam.get({teamId: id});
$scope.teamName = teamObj.name;
$scope.teamObj = teamObj;
};
}
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'main.html',
controller: 'MainController'
})
.state('team', {
url: '/team',
templateUrl: 'team.html',
controller: 'MainController'
});
console.log('ROUTECONFIG');
$urlRouterProvider.otherwise('/');
}
index.html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<!-- JS (load angular, ui-router, and our custom js file) -->
<script src="http://code.angularjs.org/1.2.13/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.8/angular-ui-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular-resource.js"></script>
<script src="app.js"></script>
</head>
<body>
<a ui-sref="home">home</a>
<a ui-sref="team">team</a>
<div ui-view=""></div>
</body>
</html>
main.html
<h1>Home</h1>
<pre>$scope.teamName => {{teamName}}</pre>
<pre>$scope.teamObj => {{teamObj}}</pre>
<pre>$scope.teamObj.name => {{teamObj.name}}</pre>
<button ng-click="getTeamInfo(1)">Get Team 1</button>
team.html
<h1>Team</h1>
<pre>$scope.teamName => {{teamName}}</pre>
<pre>$scope.teamObj => {{teamObj}}</pre>
<pre>$scope.teamObj.name => {{teamObj.name}}</pre>
<button ng-click="getTeamInfo(2)">Get Team 2</button>

Resources