Displaying content in Angular without $scope - javascript

I am trying to display content using Angular, angular UI-Router, and without relying on $scope.
In my mainController, I don't have any issues using directive likes ng-repeat. But I don't know how to access information from my postsController.
I know that I am pulling the correct data in my controller since console.log shows the correct post object. Now I just need to know how to access it.
index.html
<script type="text/ng-template" id="/posts.html" >
{{ }} // What do I put here?
</script>
app.js
app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
...
.state('posts', {
url: '/posts/{id}',
templateUrl: '/posts.html',
controller: 'postsController'
});
$urlRouterProvider.otherwise('home');
}
]);
app.js
app.controller('postsController', [
'$stateParams',
'posts',
function($stateParams, posts) {
var vm = this;
vm.post = posts.posts[$stateParams.id];
console.log(vm.post);
}
]);

You state will be using controllerAs so you need to define controller as below. And by using alias of your controller you could show data on view.
.state('posts', {
url: '/posts/{id}',
templateUrl: '/posts.html',
controller: 'postsController as postCtrl'
});
View
<script type="text/ng-template" id="/posts.html" >
<ul>
<li ng-repeat="p in postCtrl.post">{{p}}</li>
</ul>
</script>
You should have latest version like 0.2.0+ version of ui-router to declare controllerAs like I suggested, for older version you could use #RadimKöhler suggestion.

You should use declaration controllerAs:
.state('posts', {
url: '/posts/{id}',
templateUrl: '/posts.html',
controller: 'postsController',
controllerAs: 'vm' // this will be injected into $scope
});
and the view consume it like this:
{{vm.data | json }}

Related

ui-router nested view doesn't get loaded properly

Hey I have a simple app which I have created.
The app has the following views
1.Settings - Main View.
2.Profile - Sub view, child of Settings View.
3.Account - Sub View, child of Settings View.
I want the application to start from profile page, therefore I wrote the following code:
$urlRouterProvider.otherwise('/profile');
But apparently noting is happen, I got a blank screen and can't see the view properly(settings.profile).
I have added my code to a plunker to make things more convenient and accessible for other developers which can help me solve my problem.
https://plnkr.co/edit/RFP5dUNV876cy8vRDuvL?p=preview
Main main code is like this:
/**
* Module
*
* Description
*/
var app = angular.module('app', ['ui.router'])
app.controller('mainCtrl', ['$scope', function($scope){
$scope.title="Index Page";
}]);
app.controller('ProfileController', ['$scope', function($scope){
$scope.title="Profile Page";
}]);
app.controller('AccountController', ['$scope', function($scope){
$scope.title="Account Page";
}]);
app.controller('SettingsController', ['$scope', function($scope){
$scope.title="Settings Page";
}]);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('settings', {
url: '/settings',
templateUrl: 'settings.html',
controller: 'SettingsController'
})
.state('settings.profile', {
url: '/profile',
templateUrl: 'profile.html',
controller: 'ProfileController'
})
.state('settings.account', {
url: '/account',
templateUrl: 'account.html',
controller: 'AccountController'
});
$urlRouterProvider.otherwise('/profile');
});
Change the .otherwise function to:
$urlRouterProvider.otherwise('/settings/profile');
Since the other routes are nested within settings state, you can only access the nested views via the <ui-view> in settings.html. The urls are also nested within each other if url parameter is defined in both, so /settings/profile is required.
Updated Plnkr

AngularJS: UI Router doesn't load the inline template and controller

This is my first time using UI Router inside AngularJS project. I have a problem where when I click a link to view a post, it doesn't show up.
The post template is not showing and I'm still at the home page. I can see the URL flashing like http://localhost:8000/#/posts/1 and attempt to change, but, it goes back to http://localhost:8000/#/home.
Plunker: http://plnkr.co/edit/KV6lwzKUHrIZgVWVdrzt
What I am missing here?
Note 1: I already read UI Router documentation and I think I'm not missing anything.
Note 2: I'm following this tutorial (thinkster).
Note 3: I'm using SimpleHTTPServer python -m SimpleHTTPServer 8000 command to serve this project.
This is my app.js:
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/home.html',
controller: 'MainCtrl'
})
.state('posts', {
url: 'posts/:id',
templateUrl: '/posts.html',
controller: 'PostsCtrl'
});
$urlRouterProvider.otherwise('home');
}]);
...
app.controller("PostsCtrl", ["$scope", "$stateParams", "postsFactory", function($scope, $stateParams, postsFactory){
// grab the right post from postsFactory posts array
$scope.post = postsFactory.posts[$stateParams.id];
console.log($scope.post);
}]);
And this is my index.html:
<ui-view></ui-view>
...
<script type="text/ng-template" id="/posts.html">
<div class="page-header">
<h3>
<a ng-show="post.link" href="{{post.link}}">
{{post.title}}
</a>
<span ng-hide="post.link">
{{post.title}}
</span>
</h3>
</div>
</script>
Issue in your code is in your router config for posts state. It should be like below. URL should be /posts/:id instead of posts/:id.
$stateProvider
.state('posts', {
url: '/posts/:id',
templateUrl: '/posts.html',
controller: 'PostsCtrl'
});
You are basically missing / slash at the start of your posts state URL, because of / is missing it was redirecting to .otherwise rule of $urlRouterProvider
Code
.state('posts', {
url: '/posts/:id',
templateUrl: '/posts.html',
controller: 'PostsCtrl'
});
You also need to add $locationProvider.html5Mode(true); in the app.config block and <'base href="/"'> in the head section of your HTML file.
Otherwise, the #/posts/:id routing won't work.

Angular UIRouter resolve unknown provider

I'm trying to use ui-router resolve to grab some data for use in the controller:
$stateProvider
.state('home', {
url: '/',
templateUrl: 'templates/home.html',
controller: 'homeCtrl',
resolve: {
friends: ['$http', function($http) {
return $http.get('api/friends.json').then(function(response) {
return response.data;
})
}]
}
})
Here is the controller:
angular.module('app').controller('homeCtrl', ['friends', function(friends) {
this.friends = friends;
}]);
HTML:
<section ng-controller="homeCtrl as home">
<ul>
<li ng-repeat="friend in home.friends">
{{friend.name}} : {{friend.age}}
</li>
</ul>
</section>
How can I get this to work? The error I'm getting tells me define the service. Not quite sure how to do that.
Also, I know I can get it to work by injecting $scope. I am hoping to avoid that, as I am trying to learn something new here.
You have included the controller twice. Once in the HTML, and once in the ui-router. Therefore, you're actually getting two instances of the controller.
Solution: remove the controller include from the HTML, and add this to the ui-router $stateProvider:
controllerAs: 'home'

How to set ng-show on a specific element through different views/controllers?

Plunker: http://plnkr.co/edit/0efF1Av4lhZFGamxKzaO?p=preview
Below is my header, there is an ng-show="cornerLogo" which I only want to be set true on the about, login and register views, but false the home view.
<body id="body_id"
ng-app="myApp"
ng-controller="HomeCtrl">
<header>
<section ng-show="cornerLogo">
<h1>Logo</h1>
</section>
<nav id="main_nav">
<ul>
<li><a ui-sref="about">About</a></li>
<li><a ui-sref="login">Sign In</a></li>
<li><a ui-sref="register">Create Account</a></li>
</ul>
</nav>
</header>
<ui-view></ui-view>
So it works in my HomeCtrl because that is the main controller on the page.
var app = angular.module('app-home', [])
.controller('HomeCtrl', ['$scope', function($scope) {
$scope.cornerLogo = false;
}]);
However when I switch to the about, login or register views I lose that $scope
Is there a way somehow to have a global var set somewhere in my stateProvider for ui-router? Otherwise, how would you go about this issue?
var app = angular.module('bitAge',
['ui.router',
'app-header',
'app-home',
'app-about',
'app-login',
'app-register'])
.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: '_views/home.html',
controller: 'HomeCtrl',
})
.state('about', {
url: '/about',
templateUrl: '_views/about.html',
controller: 'AboutCtrl'
})
.state('login', {
url: '/login',
templateUrl: '_views/login.html',
controller: 'LoginCtrl'
})
.state('register', {
url: '/register',
templateUrl: '_views/register.html',
controller: 'RegisterCtrl'
});
// default view:
$urlRouterProvider.otherwise('/home');
}]);
Apart from my comments in the question, to fix your issue you can take this approach.
You have HomeCtrl specified as bound controller in the state registration of home partial. So instead create a main controller for your application. So that you keep the responsibilities separated out. Inject $state and expose a method called hideLogo and use $state.is to determine the logic to show/hide the logo.
i.e:
var app = angular.module('app-home')
.controller('MainCtrl', ['$scope', '$state', function($scope, $state) {
$scope.hideLogo = function(){
return $state.is('home');
}
}]);
In the index html use MainCtrl as your main controller for the app.
<body ng-app="myApp" ng-controller="MainCtrl">
<header>
<section
ng-hide="hideLogo()">
<h1>Corner Logo</h1>
</section>
Plnkr
If you want to use $state directly on the view you would need to inject it in MainCtrland set $state on the $scope object so that you can use it directly. Though i highly recommend not to use this technique, you should not expose state in the scope object and ultimately in the view. Just expose only what is needed in the viewmodel.
i.e in the MainCtrl :
var app = angular.module('app-home')
.controller('MainCtrl', ['$scope', '$state', function($scope, $state) {
$scope.$state= $state;
}]);
and just use it on the view as:
<section
ng-hide="$state.is('home')">
You can check your current state and depends on that, show or not your logo.
<section ng-show="$state.includes('home')">
<h1>Logo</h1>
</section>
Also, your anchor elements to navigate, should be like this <a ui-sref="about">About</a> and so on, because if you use normal href attribute, angular wont change state.
Also, you need to inject $state in your main module and then you can use $state module
var app = angular.module('myApp',
['ui.router',
'app-home',
'app-about']).run(function ($state,$rootScope) {
$rootScope.$state = $state;
})
UPDATE:
Here is the punklr with the answer

Defining ng-view="NAME" from RouteProvider

I'm really new to Angular and I have a little question about sending a template or URL into a ng-view. But the way I intend to do I may have to ng-view in my base template.
When my template base is like this:
<body>
<div ng-view></div>
</body>
And my JS looks like:
var app = angular.module('myApp',[])
.config(['$routeProvider', '$locationProvider', '$httpProvider', function($routeProvider, $locationProvider, $httpProvider) {
$routeProvider
.when('/home', {
templateUrl: '/contato'
})
(...)
Works fine loading URL inside ng-view when I have only ONE ng-view case, HOW ABOUT IF I need to have more then one ng-view to load ? (like: ng-view="area1" and ng-view="area2")
I've tried in each $routeProvider, but won't work:
$routeProvider
.when('/home', {
area1: {templateUrl: '/path1'},
area2: {templateUrl: '/path2'}
})
How would be the right way to set each ng-view separately?
Appreciate any help! Thanks.
Unfortunately, as you know now, you cannot have more than one ng-view on your page. You should have a look at UI-Router from AngularUI which does exactly what you are looking for (https://github.com/angular-ui/ui-router).
An example from their doc (https://github.com/angular-ui/ui-router#multiple--named-views):
setup
var myApp = angular.module('myApp', ['ui.router']);
html
<body>
<div ui-view="viewA"></div>
<div ui-view="viewB"></div>
<!-- Also a way to navigate -->
<a ui-sref="route1">Route 1</a>
<a ui-sref="route2">Route 2</a>
</body>
template 1
<h1>State 1</h1>
template 2
<h1>State 2</h1>
js
myApp.config(function($stateProvider, $routeProvider) {
$stateProvider
.state('index', {
url: "",
views: {
"viewA": { template: "index.viewA" },
"viewB": { template: "index.viewB" }
}
})
.state('route1', {
url: "/route1",
views: {
"viewA": { templateUrl: "route1.viewA.html" },
"viewB": { templateUrl: "route1.viewB.html" }
}
})
.state('route2', {
url: "/route2",
views: {
"viewA": { templateUrl: "route2.viewA.html" },
"viewB": { templateUrl: "route2.viewB.html" }
}
});
});
Here you could specify a controller at the state level, that would be effective for both views, or at the view level, in order to set two different controllers.
Edit: Live demo from ui-router docs (http://plnkr.co/edit/SDOcGS?p=preview)
Basically you can't have two ng-view. Have a look at this SO question:
You can have just one ng-view.
You can change its content in several ways: ng-include, ng-switch or mapping different controllers and templates through the routeProvider.

Categories