Displaying separate data from API in different places on page in Angular - angularjs

I have a SPA that will display data from an API in two separate parts of the page. One section displays products and prices. This information will remain on the page. The other section is a basic CRUD view. It allows the user to create new selections, read their selections, edit their selections, and remove their selections. I'm trying to determine the best way to display these two views. The CRUD section uses ng-view. Should the price/product section use a directive, a separate controller, or should I break up the page into two modules?
I'm new to Angular, and want to make sure that I do things right to avoid unforeseen issues down the road.
HTML:
<div ng-view="">
<!--user selections go here -->
</div>
<!--Product/Price info will go here. Unsure whether to insert ng-app="new module", ng-controller="new controller", or a directive with its own element-->
Javascript for user selections view:
myApp.config(function ($routeProvider) {
$routeProvider
.when('/list', {
templateUrl: 'views/list.html',
controller: 'ProjectListCtrl as projectList'
})
.when('/edit/:projectId', {
templateUrl: 'views/detail.html',
controller: 'EditProjectCtrl as editProject'
})
.when('/new', {
templateUrl: 'views/detail.html',
controller: 'NewProjectCtrl as editProject'
})
.otherwise({
redirectTo: '/'
});
});
Factory for CRUD / user form section:
myApp.factory('Projects', function($firebase, fbURL) {
return $firebase(new Firebase(fbURL+'/projects')).$asArray();
});
Factory for product list/price section:
myApp.factory('Products', function($firebase, fbURL) {
return $firebase(new Firebase(fbURL + '/products')).$asArray();
});

The native Angular router is limited when creating complex and nested UIs, but AngularUI Router is a great alternative and very widely used. If you want to include multiple views in your interface then this is the way to go. It's not much more complicated than the native router but the wins are huge.
AngularUI Router is a routing framework for AngularJS, which allows you to organize the parts of your interface into a state machine. Unlike the $route service in the Angular ngRoute module, which is organized around URL routes, UI-Router is organized around states, which may optionally have routes, as well as other behavior, attached.
Here's a Plunker to demo your particular case: http://plnkr.co/edit/xZD47L?p=preview
With ui-router you can name views
<div ui-view="viewName"></div>
and include templates and controllers in the corresponding ui-router configuration
myApp.config(function($stateProvider, $urlRouterProvider) {
// For any unmatched url, redirect to /
$urlRouterProvider.otherwise("/");
$stateProvider
.state('home',{
url: "/",
// list your views
views: {
"viewName": {
templateUrl: "viewName.html" ,
controller: "viewNameCtrl"
}
}
})
});
Checkout this Wiki for Multiple Named Views.
I hope this helps.

Related

Angular-js - dynamically create navi

I'm new to Angularjs and have sat through many tutorials to improve my knowledge. All tutorials show me how to use $routeProvider to load templates into view. However they only show me examples that assume the routes are known and I would like to learn how to dynamically create those routes so I can pull a list of unknown nav items from the db and create those routes in a loop.
So, typically a tutorial will show;
$routeProvider.when('/', {
templateUrl : 'views/home.html',
controller : 'mainController'
})
But what if I don't know what those routes will be in advance?
Unfortunately you can't create routes dynamically. You can only configure your routes in the module.config(). I think you search for routes with rest parameters.
Here an quick example with a list view and a detail view that shows one item of the list. Assume the backendService to be defined. The resulting url for the list is .../#/list and for the detail view of an item with the id 12345 the url is .../#/list/12345. Note that all route params are interpreted as strings. So routeParams will be {id: "12345"}.
In the angular phonecat step #9 is a good example of angular router.
angular.module('app').config( function($routeProvider) {
$routeProvider.when('/list',
{
templateUrl: 'views/list.html',
controller:'listCtrl'
}
).when('/list/:id',
{
templateUrl: 'views/detail.html',
controller: 'detailCtrl'
})
});
angular.module('app').controller('detailCtrl',
function($scope, $routeParams, backendService) {
$scope.items = backendService.getItemById($routeParams.id);
}
);

Use Angular Material in only a portion of a page

I am interested in using a Angular Material based contact form on a Shopify hosted page. Because the rest of the site is not built with Angular Material (yet), I would like to implement this contact form in a modular fashion, and have it isolated within its own div. The problem I've run into is that the stylesheet (currently linked in the head) for Angular Material is affecting page elements outside of the desired area of influence. Is it possible to isolate Angular Material content away from the rest of the page? How might one go about it?
You can create separate Angular module for you required template file and Inject angular material there. Link angular-material CSS in that template file only. This way It won't affect other pages.
The only way i think you can do this is by using an iframe because the css will always combine, and will follow the rule of cascade so the one that is below will override the others.
You can use angular-ui-router states with seperate angular modules. So you can inject angular-material one of the state of your routes then use it.
module.exports =
angular.module('parentModule', [
'angularMoment',
require("./childFolder"),
])
.config(function ($stateProvider) {
$stateProvider
.state('parent', {
url:"parent/",
views:{
'': {
templateUrl: 'main/layout.html',
controller: 'MainController'
}
}
})
.controller('MainController', require('./mainController'));
module.exports =
angular.module('childModule', [
'ngMateiral', 'ngMessages'
])
.config(function ($stateProvider) {
$stateProvider
.state('parent.child', {
url: "parent/:id",
views: {
'': {
templateUrl: 'main/layout.html',
controller: 'MainController'
},
'content#main': {
templateUrl: 'main/child/layout.html'
controller: 'ChildController'
}
}
});
})
.controller('ChildController', require('./childController'));

how to setup ui-router nested views

I am trying to setup my app with ui-router. I am familiar with basic nested views but I am wanting to do something more complex. I have my basic setup for the main views. I would like to have a chat popup that has its own views that are independent from the main views. I want to be able to navigate the main views and not affect the states in the chat popup. So how is this done? Do i need to have a abstract state for the chat? and then have nested views from there?
here is a visual.
and here is a plunker
plunker
$stateProvider
.state('root', {
abstract: true,
views: {
'#': {
template: '<ui-view />',
controller: 'RootCtrl',
controllerAs: 'rootCtrl'
},
'header#': {
templateUrl: 'header.html',
controller: 'HeaderCtrl',
controllerAs: 'headerCtrl'
},
'footer#': {
templateUrl: 'footer.html',
controller: 'FooterCtrl',
controllerAs: 'footerCtrl'
}
}
})
.state('root.home',{
parent:'root',
url:'/home',
templateUrl:'home.html',
controller: 'HomeController',
controllerAs:'homeCtrl'
})
.state('root.about',{
parent:'root',
url:'/about',
templateUrl:'about.html'
});
});
I suggest that, don't use footer as a ui-view, because it is completely independent of your states.
Then how?
Make your footer part as a template and use ng-include to render your footer part.
<footer ng-include="'/footer.html'"></footer>
And within footer.html you can specifies the controller for the footer view.
Benefits
No need to handle footer on each state
No need to pass chat history on every change in state.
Create Chat service/function with controllers in different js files and inject to the index.html and script.js. use bootstrap collapsible modal for pop-up chats.
Looking # your plunkr, you're on right track,though injecting controller from script.js via controllerAs is not scalable for larger app.
Instead you can create js files for each controller and service and separate partial views, just need to inject the services and controllers to index.html and mention partial views in stateprovider function.
I am not sure if You want to use route for the chat but there are two ways for you may be more
Use modals that can collabse and open when clicked like that of facebook here
Modals for bootstrap
Use angulars ngHide ngShow
For your navigation while using at sub elements on chat you can create one state for the chat and nest chat navigation in to you chat state so that any state change will not change your other chat states.
That means you will need to use substate concepts of ui-router

ionic/angularjs app construction

When making an ionic app what is the best method of creating different pages of information?
Right now I have separate html documents for each page and a button pointing to each html document; however, I feel like angular/ionic provides a better way of doing so that I missed. For example, the app I am making has a main page with buttons for 5 places. Each button loads a completely new html document with info about the place labeled on the button.
If it is too much to explain, a link answering what I am asking is fine
Thanks
What you want are angular templates. You can write a template once, and then pass in information from the controller to take the place of the angular bindings. You have one master template, that changes the angular bindings depending on which information you pass it in the controller.
For example, you could have your application load in partial templates for each location, and display them all on your main page without having to hit a new html document. Check out the example in the Angular Tutorial.
And the Live Demo
You can do it by uiROUTER, For example: angular.module('ionicApp', ['ionic']) .config(function ($stateProvider, $urlRouterProvider) { $stateProvider .state('menu', { abstract: 'true', templateUrl: 'templates/menu.html', controller: 'MenuCtrl' }) / ... / .state('menu.work', { url: '/work', views: { menuContent: { templateUrl: 'templates/work.html', controller: 'WorkCtrl' } } }); $urlRouterProvider.otherwise('/work'); });

AngularJS: Multiple views with routing without losing scope

I'm trying to implement a classic list/details UI. When clicking an item in the list, I want to display an edit form for that item while still displaying the list. I'm trying to work around Angular's 1-view-per-page limitation and decided to do it by having all URLs routed to the same controller/view. (Perhaps this is the root of my problem and I'm open to alternatives.)
Routing:
$routeProvider
.when('/list', { templateUrl: '/Partials/Users.html', controller: UserController })
.when('/edit/:UserId', { templateUrl: '/Partials/Users.html', controller: UserController })
.otherwise({ redirectTo: '/list' });
The view (/Partials/Users.html):
<!-- List of users -->
<div ng-repeat="user in Users">
Edit {{ user.Name }}
</div>
<!-- Edit form -->
<div>
{{ SelectedUser.Name }}
</div>
Controller:
function UserController($scope, $routeParams) {
// the model for the list
$scope.Users = GetUserListFromService();
// the model for the edit form
if ($routeParams.UserId != null)
$scope.SelectedUser = GetUserFromService($routeParams.UserId);
}
Problems:
When clicking an edit link, the controller is reinstantiated with a new scope, so I have to re-init the Users list. (In a more complex example I could have input from the user stored bound to the model and this would also get lost.) I'd prefer to persist the scope from the previous route.
I'd prefer to use a separate controller (or, as many other Angular developers have complained, the ability to have multiple displayed views!) but that leads to the same issue of losing scope.
Try using ui-router: http://github.com/angular-ui/ui-router.
They have nested views and easier state management than angular default routing :-)
Multiple views are not supported in core AngularJS. You can use this library for this purpose which supports any amount of nested views on the page, where each level is configured independently with its own controller and template:
http://angular-route-segment.com
It is much simpler to use than ui-router. Sample config may look like this:
$routeSegmentProvider.
when('/section1', 's1.home').
when('/section1/prefs', 's1.prefs').
when('/section1/:id', 's1.itemInfo.overview').
when('/section1/:id/edit', 's1.itemInfo.edit').
when('/section2', 's2').
segment('s1', {
templateUrl: 'templates/section1.html',
controller: MainCtrl}).
within().
segment('home', {
templateUrl: 'templates/section1/home.html'}).
segment('itemInfo', {
templateUrl: 'templates/section1/item.html',
controller: Section1ItemCtrl,
dependencies: ['id']}).
within().
segment('overview', {
templateUrl: 'templates/section1/item/overview.html'}).
segment('edit', {
templateUrl: 'templates/section1/item/edit.html'}).
up().
segment('prefs', {
templateUrl: 'templates/section1/prefs.html'}).
up().
segment('s2', {
templateUrl: 'templates/section2.html',
controller: MainCtrl});
I've found Angular Multi View to be a godsend for this scenario. It lets you preserve scope as the route changes and lets multiple controllers share the same route without nesting your views.
I recommend Angular Multi View if you have more than 2 views on your page. Otherwise, when using ui-router, nesting multiple views gets messy really fast.
I came up with the same problem and I personnaly don't like plugins when they aren't absolutely unavoidable. I just moved singleton part to a service.
In my case there are :id[/:mode] routes and I want to react different way if user changes just mode or id too. Thus, I have to know previous id.
So, there is a service with activate method which updates its state. And the scope is reinitialized every time with the following code.
module.controller('MyController', ['$scope', '$routeParams', 'navigator', function($scope, $routeParams, navigator) {
var id = null;
var mode = null;
if (typeof($routeParams.id)!='undefined')
{
id = $routeParams.id;
}
if (typeof($routeParams.mode)!='undefined')
{
mode = $routeParams.mode;
}
navigator.activate(id, mode);
$scope.items = navigator.items;
$scope.activeItem = navigator.activeItem;
$scope.modes = navigator.modes;
$scope.activeMode = navigator.activeMode;
}]);
In activate method I can compare id to the singleton's activeItem.id and react differently.

Resources