AngularJS: What is a modular approach to sidebars and sub-pages? - angularjs

I'm building an app for fun and practice, and within the app there is a dashboard module. That dashboard module houses other modules. I do this because the dashboard is the parent state for the modules inside of it and I didn't think it would be right to put them in the outside folder with all the other irrelevent modules, because they belong to the dashboard. For example:
/login
/signup
/logout
/profile
/dashboard
/home
/settings
/foo
/bar
...and their states would be dashboard.home with a url of /dashboard/home, and so forth.
In the settings folder, I have a current set up that works, but I don't know if it's considered good practice.
Under the settings directory, I have some partials and controllers. For example:
/login
/signup
/logout
/profile
/dashboard
/home
/settings
/controllers
settingsAccount.controller.js
settingsPassword.controller.js
settingsPersonal.controller.js
/partials
_account.html
_password.html
_personal.html
settings.html
settings.module.js
/foo
/bar
And those partials would be navigated through on the settings.html. How I currently do this is like this..
settings.html:
<div class="row" ng-controller="LeftSidebarController as sidebar">
<div class="col-sm-3">
<div class="page-title">
<h1 view-title>Settings</h1>
</div>
<ul class="list-group">
<li class="list-group-item" ng-class="{'active': sidebar.currentTab(1)}" ng-click="sidebar.setTab(1)">
<a href>Account</a> <i class="fa fa-chevron-right list-group-item__arrow-right"></i>
</li>
<li class="list-group-item" ng-class="{'active': sidebar.currentTab(2)}" ng-click="sidebar.setTab(2)">
<a href>Password</a> <i class="fa fa-chevron-right list-group-item__arrow-right"></i>
</li>
<li class="list-group-item" ng-class="{'active': sidebar.currentTab(3)}" ng-click="sidebar.setTab(3)">
<a href>Personal</a> <i class="fa fa-chevron-right list-group-item__arrow-right"></i>
</li>
</ul>
</div>
<div class="col-sm-7">
<div class="widget-container widget-container--settings fluid-height">
<div ng-if="sidebar.currentTab(1)"
ng-include src="'app/dashboard/settings/partials/_account.html'"
ng-controller="SettingsAccountController as account"></div>
<div ng-if="sidebar.currentTab(2)"
ng-include src="'app/dashboard/settings/partials/_password.html'"
ng-controller="SettingsPasswordController as password"></div>
<div ng-if="sidebar.currentTab(3)"
ng-include src="'app/dashboard/settings/partials/_personal.html'"
ng-controller="SettingsPersonalController as personal"></div>
</div>
</div>
</div>
...and I have a global controller LeftSidebarController, which looks like this:
(function() {
'use strict';
angular
.module('app.controllers')
.controller('LeftSidebarController', LeftSidebarController);
function LeftSidebarController() {
var vm = this;
vm.tab = 1;
vm.setTab = function(tabId) {
vm.tab = tabId;
};
vm.currentTab = function(tabId) {
return vm.tab === tabId;
};
}
})();
So as you can see, I basically just load one of the partials and attach it's controller to it based on which tab is clicked in the sidebar.
Has anyone ever had to do something like this and know a better approach? I'd really appreciate some good guidance, I don't want to make it like this because it seems really messy to me.
I thought having the sub-sub-modules, with a state of something like dashboard.settings.account, with url of /dashboard/settings/account. If I can't find a better approach I'll probably go that route, seems a bit better to me because then everything has it's own state and I will no longer be including multiple files and controllers in a single state. Only problem is I don't know how I'd handle the sidebar yet.
Thanks!

When I build an app using ui-router, I usually structure it this way:
/app
/components
/states
/login
/signup
/logout
/profile
/dashboard
states.module.js
index.html
app.module.js
app.config.js
The components folder is where I put all of my custom directives, services, filters, etc. organized by feature. For example, I might have a notifications sub-folder that contains a service and a directive.
My states folder has a file called states.module.js that would look something like this:
angular.module('app.states', [
'app.states.login',
'app.states.signup',
'app.states.logout',
// etc.
]);
Then each state sub-folder would have a module and all of the files associated with that state. It would also have a {state}.config.js file that adds the state to $stateProvider.
All of that is similar to what you have done (though I wouldn't put controllers and templates in separate folders). The key difference is, in the case of your dashboard state, I would use views.
dashboard.config.js
angular.module('app.states.dashboard')
.config(stateConfig)
;
function stateConfig($stateProvider) {
$stateProvider
.state('dashboard', {
url: '/dashboard/:view',
views: {
'home#dashboard': {
controller : 'DashboardHomeViewController',
controllerAs: 'home',
templateUrl : 'states/dashboard/home.html'
},
'settings#dashboard': {
controller : 'DashboardSettingsViewController',
controllerAs: 'settings',
templateUrl : 'states/dashboard/settings.html'
},
'': {
controller : 'DashboardViewController',
controllerAs: 'dashboard',
templateUrl : 'states/dashboard/dashboard.html'
},
}
)
;
}
I would have files in that folder for each view controller and template, as well as a module file. The main view template file would look something like this:
dashboard.html
<ui-view name="{{dashboard.view}}#dashboard"></ui-view>
Hopefully that answers your question.

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

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

IIS Virtual Directory with MVC6 Angular Routing 1.4.5

I have a MVC6/Angular site that will have multiple applications, but for now it just has one. When it is complete an example will be App1 and App2 being.cshtml pages with only a div with a data-ng-app and data-ng-view attribute:
mysite.come/virtualdir/App/App1:
<div class="row" data-ng-app="app-app1">
<div data-ng-view></div>
</div>
mysite.come/virtualdir/App/App2
<div class="row" data-ng-app="app-app2">
<div data-ng-view></div>
</div>
For angular, I understand if I have a virtual directory in IIS i need to include in my the header section of the _Layout.cshtml (Actually putting this in the _Layout will break development):
<base href="#Url.Content("~/")" />
My original templateUrl and angular links for app1 in development are:
$routeProvider.when("/", {
templateUrl: "/views/app1/index.html"
});
$routeProvider.when("/items", {
controller: "receiveController",
controllerAs: "vm",
templateUrl: "/views/app1/receiveView.html"
});
// typical link in html page for app1
<a data-ng-href="#/items"></a>
When I deploy to IIS i need to have the routing below to get to my index page to load when the the user navigates to mysite.come/virtualdir/App/App1
$routeProvider.when("/", {
templateUrl: "../views/app1/index.html"
});
After that none of my other links work:
<a data-ng-href="#/items"></a> navigates me to mysite.com/virtualDir/#/items
How do I structure my hrefs in the html page? i tried playing around with the ../#/items/ and ..#/items and adding the .. to the other templateUrl but nothing seemed to work. Thanks
so it seems like the simplest solution is to define the routes and hrefs as below. My problem was not having all three of these combinations at once. I thought angular defined the root of the angular routes based on my ~/App/App1 where I defined:
<div class="row" data-ng-app="app-app1">
<div data-ng-view></div>
</div>
so I needed in the app.js:
$routeProvider.when("/", {
templateUrl: "views/app1/index.html"
})
# the top of my _Layout.cshtml
<base href="/app/">
my href:
data-ng-href="App/App1#/items"

AngularJS with Bootstrap: Suppress redirect when clicking a modal

I have a "Contact" link in my Navbar set to open a form as a modal when clicked. This is using Bootstrap. Recently I decided to add some AngularJS routing to my site and it works great for all links except this one. My route config looks like this:
asApp.config(function($routeProvider) {
$routeProvider
// route for the home page
.when('/', {
templateUrl : 'pages/home.html',
controller : 'mainController'
})
// route for the about page
.when('/about', {
templateUrl : 'pages/about.html',
controller : 'aboutController'
})
// route otherwise
.otherwise({
templateUrl : 'pages/home.html',
controller : 'mainController'
});
});
Since I don't have a dedicated page for the contact form (it's meant to open as a modal), I haven't added any specific routing for "/contact" in the above code which is why clicking that link triggers the "route otherwise" block and redirects opens up the home page. Is there any way to suppress this routing only for the "Contact" link? I want it to stay on the page that was open when the link was clicked and the modal opened. Not sure if I have been coherent enough so please feel free to ask me if you are lost.
In case it helps, here's the modal snippet along with some other relevant HTML parts:
/* Navbar snippet */
<div class="collapse navbar-collapse" ng-controller="HeaderController">
<ul class="nav navbar-nav navbar-right">
<li ng-class="{ active: isActive('/about')}">About</li>
<li ng-class="{ active: isActive('/blog')}">Blog</li>
<li>Contact</li>
</ul>
</div>
/* Main body snippet */
<div id="main"><div ng-view></div></div>
/* Modal snippet */
<div class="modal fade" id="contact" role="dialog">
<div class="modal-dialog">
/* Contact form code here... */
</div>
</div>
Thanks a ton for your attention and help.
You could try data-target to not mess with the angular routes (url after #)
<a href data-target="#contact" data-toggle="modal">Contact</a>
There is a great module ui.bootstrap by angularUI team for using angular with bootstrap:
https://angular-ui.github.io/bootstrap/
It has a $modal service to handle opening views as a modal.
However if you don't want to use that, you can try the following:
The most simple solution will be not to have the contact as a anchor tag.
Use a div with ng-click instead.
i.e., in place of <li>Contact</li>
use <li><div class="contact-modal" ng-click="functionThatOpensModal()">Contact</div></li>
And you can style this specific div to look same as the other links.
Hope this helps

How to prevent losing data when moving from one state to another in multi-step form?

I am new to web programming and especially to AngularJS.
So maybe my question will seem naive to some of you.
I'm developing a single page application using angular-ui-router.
I have created a multi-step form that contains 3 states:
(function () {
"use strict";
angular.module("sensorManagement", ["ui.router", "ngAnimate", "ngResource", "toaster"])
.config(["$stateProvider", "$urlRouterProvider", function ($stateProvider, $urlRouterPorvider) {
$urlRouterPorvider.otherwise("/Sensor/Home");
$stateProvider
.state("MultiStepForm", {
url: "/Sensor/MuiltyStepForm",
templateUrl: "/app/MultiStepForm/MuiltyStepForm.html",
})
.state('MultiStepForm.step1', {
url: '/step1',
templateUrl: '/app/MultiStepForm/FormStep1.html'
})
.state('MultiStepForm.step2', {
url: '/step2',
templateUrl: '/app/MultiStepForm/FormStep2.html'
})
.state('MultiStepForm.step3', {
url: '/step3',
templateUrl: '/app/MultiStepForm/FormStep3.html'
});
}]);
})();
Here is the HTML code:
<!-- form.html -->
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div id="form-multiple-step">
<div class="page-header text-center">
<!-- 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=".step1"><span>STEP1</span></a>
<a ui-sref-active="active" ui-sref=".step2"><span>STEP2</span></a>
<a ui-sref-active="active" ui-sref=".step3"><span>STEP3</span></a>
</div>
</div>
<form id="single-form">
<!-- our nested state views will be injected here -->
<div id="form-views" ui-view></div>
</form>
</div>
</div>
</div>
As you can see I have 3 states and each state has it's own view. The views have multiple elements (textboxes and checkboxes).
When the user enters some data for the STEP1 view and moves to the next step (STEP2 or STEP3) then at some point goes back to STEP1 all data is deleted. I checked with fiddler and can see that when I move from one state to another a call is made to the server and a new view generated.
My question is how can I prevent the lose of data when I move from one state to another? Do I have to use caching? Or maybe there is another way to prevent server calls and keep the data alive until the submit button clicked.
When you feel you have to save data across your controllers in your app. you should use a service.
app.factory('sharedDataService', function ($rootScope) {
console.log('sharedDataService service loaded.');
// do something here that can be shared in other controller
});
//pass this service in your controller to use it there
app.controller('Controller2', ['$scope', 'sharedDataService', function ($scope, sharedData) {
console.log('Controller2 controller loaded.');
//get data from shared service
}]);
find a useful Fiddle here
Cheers if it helps!
I think what you need to do is share you $scope between the parent and child stats. here is the stackoverflow post with good example. https://stackoverflow.com/a/27699798/284225

Resources