I am a beginner in angular Js and need some help / pointers. I want to create an application (SPA). Every page of an application has a header bar and in that header bar, I have a form (like search bar) where a user can add data and search. But I am not being able to approach.
How should my approach be so that this header is present in any page of my app and I must be able to search in any page. How can this be done without code repetition? I mean I dont want to create a directive and call it in every page. I want to know if there is a proper way to do it?
The app should be like Quora where the input field for question is present in any page.
Request you to not downvote it as I am naive in Angular and need some good help.
Thank you in advance.
Search for ui-router and define some states for your application, basically you have a main states which hold header and footer, and sub states that are children of your main state.
your markup would be like this:
<header></header>
<ui-view></ui-view>
<footer></footer>
and the header can contain the search form, and all sub states are loaded in mains <ui-view>
Have you checked out ui-router?
You could define a layout/root state whose template defines multiple named ui-views. The layout/root state could load the persisting elements (ex. the search input field) into one view, and child states could load the unique page content into another view.
ex. layout.html
<div class="layout">
<div class="search" ui-view="search"></div>
<div class="content" ui-view="content"></div>
</div>
ex. state configuration (in a module's config() function)
$stateProvider.state('root', {
url: '',
views: {
'main': {
templateUrl: 'layout.html'
},
'search#root': {
template: '<input type="text" ng-model="search.input" />',
controller: ['$scope', function($scope){
$scope.search = {
input: ''
};
}]
}
}
});
$stateProvider.state('root.page1', {
views: {
'content#root': {
template: '<p>This is the first page.</p>',
}
}
})
.state('root.page2', {
views: {
'content#root': {
template: '<p>This is the second page.</p>'
}
}
});
With that config, you would need to have in your main index.html:
<div ui-view="main"></div>
Plunker Demo
Related
link to example: http://goo.gl/jJBMZL
Here two states are defined. 1. home , 2. about
home has 1 view viewA
about has 2 views viewA and viewB but viewB is a sub part of about page. I want to show viewB inside of about.html page and not on index page. Is this possible. Please provide a plunkr link thanks.
what is the best practice if there are various views and each view has sub states
You can include your page 'about-sub-level.html' inside 'about.html' using ng-include like as-
<h1>I am about page</h1>
<div ng-include="'about-sub-level.html'"> </div>
Change your routing like below-
.state('about', {
url: "/about",
views: {
"viewA": {
templateUrl: "about.html"
}
}
})
Hope this may help you..
So first off, I'm working on this for a project at work, but none of us have any idea how to do it, so it might be kind of vague.
Here is the template of how it is going to look: Template
So View A & B are going to have 3 states in them that will change the content of the view based on which one is selected
The problem I'm having is that only 1 view ever shows up and it is a test template for now because I don't have those views built but none of the sub views of View A ever show up.
HTML
<div id="main">
<div ui-view="viewa" class="col-sm-7">
<!--Content of ViewA supposed to be here-->
</div>
<div ui-view="viewb" class="col-sm-5">
<!--Content of ViewB supposed to be here-->
</div>
</div>
States:
$stateProvider.state("main", {
url: "/main",
views: {
"viewa#": {
abstract: true,
template: "<div ui-view></div>"
},
"viewb#": {
templateUrl: "btemps/default.html"
}
}
}).state("bobtheView", {
parent: "viewa",
//This is default for viewa
url: "/",
templateUrl: "atemps/bob.html",
controller: "bobController"
}).state("billtheview", {
parent: "viewa",
url: "/bill",
templateUrl: "atemps/bill.html",
controller: "billController"
}).state("joetheview", {
parent: "viewa",
url: "/joe",
templateUrl: "atemps/joe.html",
controller: "joeController"
});
//Supposed to route to viewa showing bobtheview and viewb showing the template
$urlRouterProvider.otherwise("/main/");
So when I go to the page and go to the root it redirects to the otherwise but nothing shows up, upon just going to main, only the viewb template shows up.
Any ideas? Any way I can format it better too? Is it better to go with "viewa.bobtheview" over having the parent attribute in the mix?
UPDATE: So I found a work around, I loaded each of the bobtheview, joetheview and billtheview in html partials, then I refactored it so the view state of viewa and viewb are controlled within a main template that includes the "ng-include" function to load the different templates, and since all of the data that is stored in those views is given via JSON rest requests, there is no change in the data bindings. The problem I'm facing now, is updating that "ng-include" on button click, I haven't done extensive research on it but I plan on doing so and I'll report back when/if I find something. If you have any ideas on this let me know! :D.
So I found a viable answer to the question at hand, after extensive research and asking around, I went with the option of having 1 Controller and configuration state
$stateProvider.state("main", {
url: "/",
controller: "mainController",
templateUrl: "temps/primary.html"
});
$urlRouterProvider.otherwise("/");
That went into the configuration settings, then my controller looked a little like this:
app.controller("mainController", ["$scope", "$state", "$stateParams", "$http", function($scope, $state, $stateParams, $http) {
$scope.viewatemp = $stateParams.at; //Numeric value to represent template url for viewa
$scope.viewbtemp = $stateParams.bt; //Numeric value to represent template url for viewb
//Do some other stuff here
});
Then the HTML of "temps/primary.html" looked a little something like this:
<div ui-view="viewa" class="col-sm-5" ng-include="viewatemp"></div>
<div ui-view="viewb" class="col-sm-7" ng-include="viewbtemp"></div>
I did a little manipulation of the numeric value of viewatemp and viewbtemp to get the actual URL, those are being loaded from a JSON request from my ASP.net WebApi 2 Restful service, but all in all, it is quick, rather simple and still gets the job done and allows for further enlargement of the project.
And that there in solved my problem, cool thing about this, I can have as many as these as I want because they are all separate states with nested "views"
If you do have a better answer, let me know! This is only what I found and what worked for me.
In my home:
.state('home',{
url: '',
views: {
'': {
templateUrl: 'views/main.html',
controller:'MainCtrl'
}
...
I loop through some books and also have a simple search field to filter the items:
<input type="text" ng-model="search">
<article class="items" ng-repeat="book in allBooks | filter: search" >
This works, but I would like to add the input filed inside a sidebar, and have that sidebar in a seperate view - so that I would not have to duplicate it in every view. So in my index.html I have the following code
<div ng-include ng-controller="MainCtrl" src="'views/sidebar.html'" class="sidebar"></div>
<div class="container" ui-view></div>
Assuming that this is a good practice, is there a way to add the search input field inside the sidebar, and still have it effect the loop in the home state?
Thanks
You can make the home state a nested view of the sidebar. The ng-model that your filter is bound to in the sidebar view will then be available to the home state. The home state will delegate to the above sidebar scope when it doesn't find a search property on its own scope.
Here's my quick and dirty example:
http://plnkr.co/gmUaDLSfJxOL42EPZ9ak
Intro
I'm using AngularJS with the AngularUI module to build an admin interface with several views.
I have a simple Layout for public pages which has one ui-view and another one for admin pages which has four ui-views (header, sidebar, main, footer).
Problem
The problem I have is if I set the ui-view main the public state won't display the login view, but if I won't set the ui-view main the public state will display the login view. The header, sidebar and footer work with any setting. It seems some setting is overriding another even I tried to set absolute names. Could someone explain what's going on here?
ui-view="main" ==> Login doesn't show
ui-view="" ==> Login shows
Visual layout:
Source code (index.html):
<body>
...
<div ui-view="public">
</div>
<div class="admin">
<div ui-view="header"></div>
<div ui-view="sidebar"></div>
<div class="container" style="margin-top:60px" ui-view="">
<!-- ^ add main here -->
</div>
<div ui-view="footer"></div>
</div>
...
</body>
Code example
I set up a minimal full code example to outline the problem:
Plunker Edit
Plunker Run
I've played around with your demo a little bit and had a look at the ui-router documentation.
If you change your 'public' state as shown below then it seems to work.
Original:
.state('public', {
url: '/login',
title: 'Login',
templateUrl: 'login.html'
})
Updated:
.state('public', {
url: '/login',
views: {
'main#': {
title: 'Login',
templateUrl: 'login.html'
}
}
})
Here is an updated plunkr:
http://plnkr.co/edit/okBWMPpWysS9srKrcxeG?p=preview
Is that what you're trying to do, or are you trying to set up login as a nested view?
<div id="header">
Header
</div>
<div id="wrapper">
<div id="slider" ng-view>
Slider
</div>
<div id="mainWindow" ng-view>
Main window
</div>
</div>
http://jsfiddle.net/abehnaz/k9Y4f/
I am working with a webapp that has two major views. The first is a main window (standard stuff), and the second is a "slider". The slider is more than a slide out menu (sometimes called a "shelf"). It has routing and secondary information associated with it.
In what seems to be the normal Angular paradigm, I would use a single ng-view in the main window, and that would populate the main window with the results of the $routeProvider's view template.
However, here I want to be able to ALSO have the slider have its own route. Angular does not seem to support this. I was thinking that I could potentially hack the functionality in by making a client side URL of the form:
www.app.com/MAINWINDOW/someView1/someView2/SLIDER/someViewa
Am I on the right track with this, or is there another functionality of Angular that I can use?
I would not recommend two routeParameters. Make your sidebar a service and put a controller on your wrapper, slider, and mainWindow. By having the ng-controller on #wrapper as well as the children, you can share data between the controllers (and in turn, inject the service into those controllers. I have done this and it was very successful. See an example below. In my code, my ng-view and routing returned everything within the <div ng-app="myApp">. You could easily put the ng-view in the MainCtrl and trigger routes from the sidebar.
In your template:
<div ng-app="myApp">
<div ng-view>
//Produced by routing
<div id="wrapper" ng-controller="RootCtrl">
<div id="Sidebar" ng-controller="SidebarCtrl">
...
<div ng-click="setUnit(mod.number, unit.number)">Unit 1</div>
...
</div>
<div id="mainWindow" ng-controller="MainCtrl">
</div>
</div>
</div>
</div>
In your javascript:
A service:
myApp.service('questionsSvc', function(Modules) {
var QuestionsSrc = {};
QuestionsSrc.questions = [];
var getQuestionsForModAndUnitFn = function(mod, unit) {
...bunch of code to have it populate QuestionSrc with questions
};
return {
getQuestionsForModAndUnit: getQuestionsForModAndUnitFn,
Questions: QuestionsSrc
};
});
For Controllers:
function RootCtrl($scope) {
$scope.data = {};
}
function SidebarCtrl($scope, Modules, questionsSvc) {
$scope.setUnit = function (mod, unit) {
questionsSvc.getQuestionsForModAndUnit(mod, unit);
$scope.data.questions = questionsSvc.Questions.questions;
//$scope.data.questions was used in the MainCtrl window to do an ng-repeat on the json array of questions bound to this model.
}
};
function MainCtrl($scope){
...whatever you need to manipulate the code...
}
With this example, I am sharing information across Controllers. The magic is with the $scope.data = {}; from the RootCtrl. It allows me to attach questions to the $scope based on an action in the Sidebar (clicking a label) and use that same $scope in the MainCtrl to display the questions in a pretty format. With what I just showed, I did not have to use $routeParameters to pass variables to go to another page (such as module and quiz) but I could have done so as you asked but would have had the sidebar ng-click change routes.
Hope this helps.
One solution is to use Angular UI router:
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 Angular core, which is organized around
URL routes, UI-Router is organized around states, which may optionally
have routes, as well as other behavior, attached.
States are bound to named, nested and parallel views, allowing you to
powerfully manage your application's interface.
Just to give a flavor for how you could use AngularUI Router- It supports multiple named views (which you can read more about under "Multiple & Named Views" in their docs). So for instance you can use ui-view with names:
<div id="wrapper">
<div id="slider" ui-view="slider">
Slider
</div>
<div id="mainWindow" ui-view="main">
Main window
</div>
</div>
Then within config you can attach states to various routes and specify what each view should display for that state.
myapp.config(function($stateProvider, $urlRouterProvider){
$stateProvider
.state('index', {
url: "/index",
views: {
"Slider": {
templateUrl:"route1.viewA.html"
},
"Main": {
templateUrl:"main1.viewA.html"
}
}
})
.state('slider2', {
url: "/slider2",
views: {
"Slider": {
templateUrl:"route2.viewA.html"
},
"Main": {
templateUrl:"main1.viewA.html"
}
}
})
There's a variety of other ways you could use AngularUI Router though. For instance, you may be able to get away with just using nested routes- which they recommend trying first.
Here's a couple more good reference material you might check out:
http://joelhooks.com/blog/2013/07/22/the-basics-of-using-ui-router-with-angularjs/
http://www.ng-newsletter.com/posts/angular-ui-router.html