Angular UI-Router Help - Show Elements Based On State - angularjs

First off I am new to angular and I am inheriting this project. This seems like it should be deathly easy to say if the state is this show this, but I keep failing :]
angular.module('myApp')
.config(function ($stateProvider) {
$stateProvider
.state('page1', {
url: '/page1',
data: etc..................
},
.state('page1.nest', {
url: '/page1/nest',
data: etc..................
},
.state('page2', {
url: '/page2',
data: etc..................
},
Each page has it's own controller. page1 and page1 nest share the same templateUrl: 'scripts/app/page.html'. The div below lives on the page.html.
How do I simple say...
<div>
<span ng-show="if state == page1">Page 1</span>
<span ng-show="if state == page1/nest">Page 1 Nest</span>
</div>
<div>
Same Content on both here
</div>
I think it has something to do with $stateParams needing to be exposed to the scope in the controller?

You'll want to use the $state service provided by UI-Router
Check the documentation out here.
You'll do something like
In your controller. Inject $state then set it to a scope variable
$scope.state = $state
Then you can do something like this.
<span ng-show="state.is('page1')">Page 1</span>
Alternatively obviously you can use a function in your controller.
<span ng-if="inState('page1')">Page 1</span>
In controller
$scope.inState = function(state){
return $state.is(state);
}

Let's start first by formatting your code a little better and closing parens where they should be closed.
angular.module('myApp')
.config(function($stateProvider) {
$stateProvider
.state('page1', {
url: '/page1',
template: 'templates/page1.html',
data: etc..................
}),
.state('page1.nest', {
url: '/page1/nest',
template: 'templates/page1.nest.html',
data: etc..................
}),
.state('page2', {
url: '/page2',
template: 'templates/page2.html',
data: etc..................
});
Typically you would have these various templates somewhere in your project structure like
/app
/templates
Then you have your index page...
<html ng-app>
<body>
<div ng-controller="myController">
<div ui-view></div> <!-- this is where the page1 or page2 state gets loaded -->
</div>
</body>
</html>
Then in your page1 or page2 html files
<div>
... content goes here ...
<div ui-view></div> <!-- nested content will go in here -->
</div>
Then in your page1.nest.html
<div>
... all your nested content goes here
</div>

Related

ui-router Main View is rendering thrice and no controller are registering

I am trying to create a SPA using angular ui-router with MVC. I am facing three issues.
1.The controllers OfferController.js and OfferCustomizationController.js are not registering.
2.I am getting the errors ' No reference point given for path '.offer', No reference point given for path '.customizations'.
3. Main view is rendering thrice.
I have no clue what am i missing. Please help.
I have included the following files in my Layout.cshtml:
<script src="#Links.Scripts.angular_min_js"></script>
<script src="#Links.Scripts.ProductCatalog.app_js"></script>
<script src="#Links.Scripts.ProductCatalog.service_js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular-animate.min.js"></script>
I have made two views. Offers And OfferCustomizations. And a main view. Following is my code for the main view:
<div class="inside-data-div" ng-app="ProductCatalog">
#*<div ui-view></div>*#
<div class="col-lg-12">
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div id="form-container">
<div class="page-header text-center">
<h2>Create Offer</h2>
<!-- the links to our nested states using relative paths -->
<!-- add the active class if the state matches our ui-sref -->
<div id="status-buttons" class="text-center">
<a ui-sref-active="active" ui-sref=".offer"><span>1</span> Offer Details</a>
<a ui-sref-active="active" ui-sref=".customizations"><span>2</span> Offer Customizations</a>
</div>
</div>
<!-- use ng-submit to catch the form submission and use our Angular function -->
<form id="signup-form" ng-submit="SaveForm()">
<!-- our nested state views will be injected here -->
<div id="form-views" ui-view></div>
</form>
</div>
<!-- show our formData as it is being typed -->
<pre>
{{ formData }}
</pre>
</div>
</div>
</div>
</div>
Following is my code of app js:
var productCatalogApp = angular.module('ProductCatalog', ['ui.router']);
productCatalogApp.value('appName', 'Product Catalog');
productCatalogApp.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show our basic form (/form)
.state('wizard', {
url: '/wizard',
templateUrl: 'WizardSubForm',
controller: 'WizardMainController'
})
// nested states
// each of these sections will have their own view
// url will be nested (/form/profile)
.state('wizard.offer', {
url: '/offer',
templateUrl: 'OfferForm',
controller: 'OfferCtrlr'
})
// url will be /form/interests
.state('wizard.customizations', {
url: '/customizations',
templateUrl: 'OfferCustomizations',
controller: 'CustomizationCtrlr'
});
// catch all route
// send users to the form page
$urlRouterProvider.otherwise('/wizard/offer');
});
productCatalogApp.controller('WizardMainController', function ($scope) {
// we will store all of our form data in this object
$scope.formData = {};
// function to process the form
$scope.SaveForm = function () {
alert('awesome!');
$scope.formData = { "Offer": $scope.offer, QuestionGroups: $scope.QuestionGroups }
};
});
This is how i'm registering my controllers. Below is the one for offercontroller.
var app = angular.module('ProductCatalog.controllers', []);
app.controller('OfferCtrlr', function ($scope, $http, $modal) {
});
Any help will be appreciated.

How to use 1 ui-view if there are multiple ui-view elements with the same name?

I have a html structure like so,
<div class="content-wrapper">
<div class="content">
Click me
</div>
<div ui-view="content-view">Template goes here</div>
</div>
<div class="content-wrapper">
<div class="content">
Click me
</div>
<div ui-view="content-view">Template goes here</div>
</div>
Two content-wrapper divs with both a ui-view called content-view.
And my state config looks like this,
$stateProvider
.state('home', {
url: ''
})
$stateProvider
.state('content-view', {
url: '',
views: {
"content-view": {
template: '<div>Content</div>',
}
},
})
See it in action here > http://plnkr.co/edit/997KbH9beLLHClM0IKb9?p=preview
If a user clicks on one of two ui-sref elements both the ui-view 'content-view` elements get triggered and inject the template.
What I would like to see is that only the ui-view in the content-wrapper element that gets clicked gets triggered.
Hiding one or the other element wouldn't be a good solution, because then the views will still have to load all the data in them. So I think my best bet is to target the specific ui-view in the same content-wrapper element.
* Update *
I've updated my plunker > http://plnkr.co/edit/997KbH9beLLHClM0IKb9?p=preview
I create several rows with content divs in them. Each row has 1 ui-view element. If a user clicks on one of the links it places the template in each view. While I want to target the view that's inside the content wrapper that the user clicked on.
Instead of nested views you can use directive here as you have repeating same objects so nested views do not help you that much...
just define a directive which is only for templating (of course you can extend its feature by your needs)..,
app.directive('contentTemplate', function() {
return {
restrict: 'E',
template: '<div class="content-view">{{vm.movie.title || "No Movie"}} is selected</div>',
scope: {
movie: '='
},
controller: ContentTemplateController,
controllerAs: 'vm',
bindToController: true
}
})
function ContentTemplateController() {
// your directive controller if you need it
}
then bind your selected content with directive then whenever you change movie content of directive will be changed as well...
<div class="content-wrapper" ng-repeat="movieGroup in movieGroups">
<div class="content" ng-repeat="movie in movieGroup">
<button ng-click="movieGroup.selectedMovie = movie;">{{ movie.title }}</button>
</div>
<content-template movie="movieGroup.selectedMovie"></content-template>
</div>
Creating independent ui-view states with the same name is simply not possible with the current model that ui-router has provided. The closest possible implementation is probably ui-router-extras's sticky module. You can create multiple independent(sticky) states by taking advantage of multiple named views in a state.
DEMO
Javascript
app = angular.module('myApp', [
'ui.router',
'ct.ui.router.extras'
]);
app.controller('mainCtrl', ['$scope',
function($scope){}
])
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: '/'
})
.state('main.sub1', {
sticky: true,
views: {
'sub1#': {
template: 'sub1<ui-view />'
}
}
})
.state('main.sub1.part1', {
template: '.part1'
})
.state('main.sub2', {
sticky: true,
views: {
'sub2#': {
template: 'sub2<ui-view />'
}
}
})
.state('main.sub2.part1', {
template: '.part1'
});
});
HTML
<div class="content-wrapper">
<div class="content">
<a ui-sref="main.sub1">main.sub1</a> |
<a ui-sref="main.sub1.part1">main.sub1.part1</a>
</div>
<div ui-view="sub1">Template goes here</div>
</div>
<div class="content-wrapper">
<div class="content">
<a ui-sref="main.sub2">main.sub2</a> |
<a ui-sref="main.sub2.part1">main.sub2.part1</a>
</div>
<div ui-view="sub2">Template goes here</div>
</div>

Angular ui-router on wordpress page

I'm developing on http://localhost:3000/af2015/web/ (the extra directories will not be present on the production site) and using wordpress. My Angular app is on the /recommendations page, which includes this template:
<div ng-app="af2015App">
<div ng-controller="MapCtrl as vm">
<map center="[52.374, 4.899]" zoom="12">
</map>
</div>
<section>
<div ui-view>
</div>
</section>
</div>
The ui-view template is not being loaded, nor the controller being initialised. This is my config function, and I have tried all sorts of permutations of <base href="/af2015/web" /> tag. There are no errors in my console.
angular.module('af2015App')
.config(function($stateProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$stateProvider.state('list', {
//url: '/:alpha/:beta/:gamma',
url: '/recommendations',
template: '<h2>List</h2>',
controller: "ListController",
controllerAs: 'list'
});
});
Didn't try enough permutations. This one worked:
<base href="/af2015/web/recommendations/" />
And then
$stateProvider.state('list', {
url: '/',

Could not resolve '___' from state 'home' - angular ui-router issue

I'm new to angular and following this tutorial:
https://scotch.io/tutorials/angularjs-multi-step-form-using-ui-router
but i'm injecting this module into another existing module.
However, I keep getting a "could not resolve states" error - I'm not sure why but suspect its either a routes issue and I'm being dumb, or otherwise its a nested views issue (note nesting of ui-view in index.html, and again in home.html).
using angular ui version 0.2.13
angular version 1.3.14
Please help!!
Below is the relevant code:
structure:
home.html
<div id="form-container">
<div class="page-header text-center">
<h2>Let's Be Friends</h2>
<!-- the links to our nested states using relative paths -->
<!-- add the active class if the state matches our ui-sref -->
<div id="status-buttons" class="text-center">
<a ui-sref-active="active" ui-sref=".profile"><span>1</span> Profile</a>
<a ui-sref-active="active" ui-sref=".interests"><span>2</span> Interests</a>
<a ui-sref-active="active" ui-sref=".payment"><span>3</span> Payment</a>
</div>
</div>
<!-- use ng-submit to catch the form submission and use our Angular function -->
<form id="signup-form" ng-submit="processForm()">
<!-- our nested state views will be injected here -->
<div id="form-views" ui-view></div>
</form>
</div>
<!-- show our formData as it is being typed -->
<pre>
{{ formData }}
</pre>
index.html
<body> blah blah
<div ui-view></div>
<script src="app.js"></script>
<script src="javascripts/form.js"></script>
<script src="controllers/main.js"></script>
<script src="controllers/form-controller.js"></script>
</body
app.js
angular.module('MyApp', ['ngCookies','ngResource', 'ngMessages', 'mgcrea.ngStrap', 'formApp'])
.config(['$locationProvider', '$stateProvider', function($locationProvider, $stateProvider){
$locationProvider.html5Mode(true);
console.log($stateProvider);
}]);
form.js
angular.module('formApp', ['ngAnimate', 'ui.router'])
// configuring our routes
// =============================================================================
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show our basic form (/form)
.state('home', {
url: '/',
templateUrl: 'views/home.html',
controller: 'formController'
})
// nested states
// each of these sections will have their own view
// url will be nested (/form/profile)
.state('.profile', {
url: '/profile',
templateUrl: 'views/form-profile.html'
})
// url will be /form/interests
.state('.interests', {
url: '/interests',
templateUrl: 'views/form-interests.html'
})
// url will be /form/payment
.state('.payment', {
url: '/payment',
templateUrl: 'views/form-payment.html'
});
// catch all route
// send users to the form page
$urlRouterProvider.otherwise('/');
})
form-controller.js
// our controller for the form
// =============================================================================
angular.module('formApp')
.controller('formController', ['$scope', function($scope) {
// we will store all of our form data in this object
$scope.formData = {};
// function to process the form
$scope.processForm = function() {
alert('awesome!');
};
}]);
Your code is not following the tutorial exactly. Note that for child states to function, they must reference their parent state.
In the tutorial code:
.state('form.profile', {
In your code:
.state('.profile', {
If you change your child states to reference the parent, they will function correctly. i.e.
.state('home.profile', {

How can I create a link in an angular app that loads inside a tab?

I have a link in an angular app that looks like this:
<tab ng-controller="childCtrl" heading="Children">
edit
</tab>
How can I load the link inside the tab instead of refreshing the entire view?
I like other approach with one point of handling all routes. ui.router with nested views allows to do it.
Template
<div ><a ui-sref="home.tab1" >Tab1</a></div>
<div><a ui-sref="home.tab2" >Tab2</a></div>
<br>
<div ui-view="tabs"></div>
app
var app = angular.module('plunker', ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'main.html',
controller: 'MainCtrl',
virtual: true
})
.state('home.tab1', {
url: '/tab1',
views: {
tabs: {
templateUrl: '1.html'
}
}
})
.state('home.tab2', {
url: '/tab2',
views: {
tabs: {
templateUrl: '2.html'
}
}
});
$urlRouterProvider
.otherwise('/home/tab1');
})
And demo http://plnkr.co/edit/r1jPgkMnPAMlI34gZrMA?refresh&p=preview
You could define the path to the selected tab's content when the link is clicked, and use ng-include to display it.
<div ng-repeat="parent in parents">
<div ng-repeat="child in parent.children">
<a href="" ng-click="selectPath(parent, child);">
Parent {{parent.Id}}, Child {{child.Id}}
</a>
</div>
</div>
<div ng-include="selected.path"></div>
Here is a demo: http://plnkr.co/edit/7SPnluxUfcNNQDyeC6yt?p=preview

Resources