I am following MVA intro to Angularjs. I have two questions. First; is there any better tutorial website that you would suggest.
Second is using ui-router. I have been looking at it for hours; went looking for the answer, and just cant figure out what could possibly be wrong. Everything looks like the tutorial; the library came off of it; and everything was working in till I switched ng-route with ui-router(and all the href with ui-sref). I think the problem is in the mainApp module since the page is white (when I have had problems with the mainPageModule the navbar would show up but it would have {{event.something[0]}} listed across the top). This is driving me crazy.
index.html
<div ng-include src="'app/event/directives/header.html'"></div>
<div class="container">
<ui-view></ui-view>
</div>
<script src="./app/angular.min.js"></script>
<script src="./app/mainApp.js"></script>
<script src="./app/ui.router.js"></script>
<script src="./app/event/mainpageModule.js"></script>
<script type="text/javascript">
console.log("angular object",angular);
</script>
</body>
mainApp.js
angular.module('mainApp', ['mainPageModule','ui.router'])
.config(['$urlRouterProvider','$stateProvider',
function ($urlRouterProvider, $stateProvider) {
$stateProvider
.state("home", {
url: "/home",
templateUrl: 'main.html'
})
.state("area", {
url: "/area",
templateUrl: "area.html"
})
.state("personal", {
url: "/personal"
templateUrl: "personal.html"
})
.state("contact", {
url: "/contact"
templateUrl: "contact.html"
})
$urlRouterProvider.otherwise('','/home')
}])
.run([function () {
/* Run is when the app gets kicked off*/
console.log("Run hook");
}])
mainPageModule.js
(function(){
angular.module('mainPageModule', [])
.factory('SiteName', [function () {
return {
title:"Website Name"
};
}])
.config([function () {
console.log("Event Module:: config");
}])
.run([function () {
console.log("Event Module::running");
}])
.controller('navigationbarController', ['$scope', 'SiteName',function ($scope,SiteName)
{ this.menu=[
{
name:"Website Name",
href:"home.html"
},
{
name:"Your Area",
href:"area.html"
},
{
name:"Personal",
href:"personal.html"
},
{
name:"Contact",
href:"contact.html"
}
]
this.index = 0;
this.setIndex=function(val)
{
this.index = val;
console.log("called")
}
this.getIndex=function(){
return(this.index);
}
}])
})();
header.html
<nav ng-controller="navigationbarController as event" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">{{event.title}}</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li ng-click="setIndex(0)" ng-class="(index==0) ? 'active' : ''">
<a ui.sref="home">{{event.menu[0].name}}</a>
</li>
<li ng-click="setIndex(1)" ng-class="(index==1) ? 'active' : ''">
<a ui.sref="area">{{event.menu[1].name}}</a>
</li>
<li ng-click="setIndex(1)" ng-class="(index==1) ? 'active' : ''">
<a ui.sref="personal">{{event.menu[2].name}}</a>
</li>
<li ng-click="setIndex(1)" ng-class="(index==1) ? 'active' : ''">
<a ui.sref="contact">{{event.menu[3].name}}</a>
</li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
<!-- /.container -->
</nav>
As suggested by #TOM you need to load angular-ui-router right after angular.js has loaded thereafter you could load mainApp.js.
You need to replace your all ui-sref directive at all places.
ui-sref="home" instead of ui.sref="home"
For anybody else who has this problem, the fundamental flaw was the order of the scripts at the bottom of the page. It matters. Second, my script mistake was not including comma's after the url's in the mainApp. Moving forward, I replaced all the ui.sref's with ui-sref's and it did work.
Thanks for your help, pankajparkar and Tom was great. Anyone else who is starting out and run's into thisproblem, check the console, it will tell you whats wrong
Related
I have an issue with the <a href="#"> in my AngularJS app.
My main issue is on the:
<em class="fa fa-bars"></em>
navigation.html -> this is a template of navigation directive.
<nav class="sidebar col-xs-12 col-sm-4 col-lg-3 col-xl-2 bg-faded sidebar-style-1">
<h1 class="site-title"><em class="fa fa-rocket"></em> Brand.name</h1>
<em class="fa fa-bars"></em>
<ul class="nav nav-pills flex-column sidebar-nav">
<li class="nav-item"><a class="nav-link active" href="index.html"><em class="fa fa-dashboard"></em> Dashboard <span class="sr-only">(current)</span></a></li>
</ul>
<em class="fa fa-power-off"></em> Signout</nav>
index.html
<body ng-app="test" class="body-bg" ng-style="bgimg" ui-view>
</body>
app.js
var app = angular.module("test", ["ui.router");
app.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
$stateProvider
// login route
.state("login", {
url:"/",
controller: "LoginController",
templateUrl: "pages/login/login.html"
})
// admin route
.state("admin", {
url:"/admin",
controller: "AdminController",
templateUrl: "pages/admin/admin.html"
})
And currently I am doing a SPA routing using ui-sref of ui-router.
The problem is everytime I click the button, I get redirected to the default state $urlRouterProvider.otherwise('/');.
How I can do something similar to that HTML href="#" with AngularJS ui-sref?
Or is there other ways?
from the code in the question I can say that, the normal usage of href will result in redirection so you need to use data-target, can you please try this?
<a data-target="#menu-toggle" data-toggle="collapse" class="btn btn-default"><em class="fa fa-bars"></em></a>
JSFiddle: here
if you have jQuery (which you probably do)
inside your head tag...
<script>
$(document).ready(function(){
$('[href="#menu-toggle"]').click(function(event){
event.preventDefault();
})
});
</script>
Basically keeps the link from routing via window navigation.
You can easily test by pasting this code into your browser console..
$('[href="#menu-toggle"]').click(function(event){
event.preventDefault();
})
You can use a combination of href and ng-click to solve your problem.
<em class="fa fa-power-off"></em> Signout</nav>
Where signOut() is a function on your controller.
1.Just remove the href tag completely from your anchor tag. It's still a perfectly valid tag without it. (or) href="javascript:void(0);"
for your reference: Angular-UI-Router: should i avoid href with ui-router?
Here is my html:
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="/" data-toggle="collapse" data-target="#navbar">
{{chooseScriptLevel
'Home'
'zhŭyè'
'主页'
}}
</a></li>
</ul>
</div>
Here is my helper:
Template.registerHelper('chooseScriptLevel', function (english, pinyin, simplified) {
var userSkillLevel = Meteor.user().profile.skillLevel
switch (userSkillLevel) {
case 0:
return english
break
case 1:
var ruby = '<ruby>' + simplified + '<rt>' + pinyin + '</rt></ruby>'
return ruby
break
case 3:
return simplified
break
default:
english
}
})
My navbar is showing: <ruby>主页<rt>zhŭyè</rt></ruby>. Literally showing the html tags to the user.
How can I get it to show the user this:
zhŭyè
主页
If I do it manually, like this, , it works:
<li><a href="/" data-toggle="collapse" data-target="#navbar">
<ruby>主页<rt>zhŭyè</rt></ruby>
</a></li>
Just use triple braces around your helper - this is necessary if the helper returns html:
{{{chooseScriptLevel 'Home' 'zhŭyè' '主页' }}}
I have three pages with routing. If I entered some input and getting some result on first page, next I navigated to second page and finally I came back from second page to first page. Then I want to see the data what I entered previously and result also.
Here the code snippet
index.html
<!DOCTYPE html>
<html ng-app="scotchApp">
<head>
<script src="angular.min.js"></script>
<script src="angular-route.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="mainController">
<nav class="navbar navbar-default">
<div class="container"></div>
<ul class="nav navbar-nav navbar-right">
<li><i class="fa fa-home"></i> Home</li>
<li><i class="fa fa-shield"></i> About</li>
<li><i class="fa fa-comment"></i> Contact</li>
</ul>
</div>
</nav>
<div id="main">
<div ng-view></div>
</div>
</body>
</html>
home.html
<div class="jumbotron text-center">
<h1>Home Page</h1>
Billing index :
<input type="text" ng-model='billingMapValue'>
<br/><br/>
Billing value :
{{billingMap[billingMapValue]}}
<ng-click=navigate() type="button" value='submit'>
<p>{{ message }}</p>
</div>
about.html
<div class="jumbotron text-center">
<h1>About Page</h1>
<p>{{ message }}</p>
</div>
script.js
var scotchApp = angular.module('scotchApp', [ 'ngRoute' ]);
scotchApp.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'home.html',
controller : 'mainController'
})
.when('/about', {
templateUrl : 'about.html',
controller : 'mainController'
})
.when('/contact', {
templateUrl : 'contact.html',
controller : 'mainController'
});
});
scotchApp.controller('mainController', function($scope) {
$scope.message = 'Everyone come and see how good I look!';
$scope.billingMapValue = "";
$scope.billingMap = new Array();
$scope.billingMap["ZF2"] = "Invoice";
$scope.billingMap["ZRE"] = "Credit for Returns";
$scope.billingMap["ZG2"] = "Credit Memo";
$scope.billingMap["ZL2"] = "Debit Memo";
$scope.billingMap["ZS2"] = "Cancellation of Credit Memo";
$scope.billingMap["ZS1"] = "Cancel. Invoice (S1)";
});
Now what I need is. If I run index.html page, I will be in home page there is one input text box. If enter some index value like 'ZF2' I will see the value "invoice". there will be list of hyperlinks on top of page .home, .about and .contact. I will click about item then I navigate to about page. Then I navigate again to home page by clicking home hyperlink , now I need to see the previous data which I entered and got.How to do that?
Thanks in advance.
I'd suggest you to use service, that will act as sharable resource between the different controllers.
You need to do some changes in your code.
You need to move all the static to either service or angular constant.
Use dot rule while binding object that will udpate your binding automatically.
Assign a different controller for each view, that would be more modular approach.
Service
scotchApp.service('dataService', function() {
this.data = {}
this.data.billingMap = new Array();
this.data.billingMap["ZF2"] = "Invoice";
this.data.billingMap["ZRE"] = "Credit for Returns";
this.data.billingMap["ZG2"] = "Credit Memo";
this.data.billingMap["ZL2"] = "Debit Memo";
this.data.billingMap["ZS2"] = "Cancellation of Credit Memo";
this.data.billingMap["ZS1"] = "Cancel. Invoice (S1)";
this.data.selectedBillMap = '';
});
Controller
scotchApp.controller('mainController', function($scope, dataService) {
$scope.message = 'Everyone come and see how good I look!';
$scope.billingData = dataService.data.billingMap;
});
Demo Plunkr
I'm having trouble figuring out how to have dynamic data only update when the user selects from the typeahead menu or clicks the search button.
Right now, the dynamic content pertaining to the search query updates automatically when the input value is changed (content disappears). I want the content to stay in view until a new selection has been either clicked in the typeahead list or clicked by the search button.
Any insight at all would be greatly appreciated! Thank you!
Plunker demo:
http://plnkr.co/edit/jVmHwIwJ0KOKCnX6QjVa?p=preview
Code:
<!-- HTML -->
<body ng-controller="MainController">
<!-- Search -->
<div class="well">
<p>Search the term "content"</p>
<form role="form">
<div class="form-group clearfix search">
<input type="text" ng-model="selectedContent" ng-options="query as query.searchQuery for query in searchData" bs-typeahead="bs-typeahead" class="form-control search-field"/>
<button type="button" class="btn btn-primary search-btn"><span class="glyphicon glyphicon-search"></span></button>
</div>
</form>
</div>
<!-- Dynamic Content -->
<div class="well">
<h4>{{ selectedContent.contentTitle }}</h4>
<ul>
<li ng-repeat="item in selectedContent.headlines">{{item.headline}}</li>
</ul>
</div>
<!-- typeahead template -->
<ul class="typeahead dropdown-menu" tabindex="-1" ng-show="$isVisible()" role="select">
<li role="presentation" ng-repeat="match in $matches" ng-class="{active: $index == $activeIndex}">
</li>
<!-- JS -->
var app = angular.module('demoApp', ['ngAnimate', 'ngSanitize', 'mgcrea.ngStrap'])
.config(function ($typeaheadProvider) {
angular.extend($typeaheadProvider.defaults, {
template: 'ngstrapTypeahead.html',
container: 'body'
});
});
function MainController($scope, $templateCache, $http) {
$scope.selectedContent = '';
$http.get('searchData.json').then(function(response){
$scope.searchData = response.data;
return $scope.searchData;
});
};
You could use a directive such as this:
app.directive('mySearch', function(){
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, $element, $attrs, ngModel){
ngModel.$render = function(){
if (angular.isObject($scope.selectedContent)) {
$scope.clickedContent = $scope.selectedContent;
}
}
$scope.updateModel = function() {
$scope.clickedContent = $scope.selectedContent;
}
}
}
})
plunker
Edit:
I added using the ngModelController. The function you set ngModel.$render to gets called whenever the model updates. If you click the typahead popup, then the model selectedContent will be an object, otherwise it'll be a string. If it's an object (meaning the user clicked the typahead popup) we do the same as we did in the updateModel function.
I'm new to ember and trying to build a Ember driven web application. I've read various tuts and studies several examples. The basic concepts are clear but now I'am stuck on trying to implement a tabpanel. My approach is as follows:
View
Configurator.TabPanelView = Ember.View.extend({
classNames: ['tabPanel'],
templateName: 'tabPanel'
});
Template
<script type="text/x-handlebars" data-template-name='tabPanel'>
<div class='tabHead'>
<ul>
{{#each tabViews}}
<li {{action "{{this.actionName}}" target="{{this.value}}"}} >{{this.title}}</li>
{{/each}}
</ul>
<div class="tab-content">{{outlet}}</div>
</div>
</script>
Usage in App
var tab= Configurator.TabPanelView.create({
classNames: ['assortment'],
tabViews: [{ title: 'First', value:'Foo', actionName: 'firstTab' },{title: 'Second', value:'Foo', actionName: 'secondTab' }],
firstTab: Ember.View.extend({
templateName: 'first'
}),
secondTab: Ember.View.extend({
templateName: 'second'
})
});
tab.appendTo("body");
The TabTemplate is rendered correctly but if I try to click on the li-elements following error is thrown
Uncaught Error: assertion failed: Target <(subclass of
Ember.View):ember217> does not have action {{this.actionName}}
I'm also curious if I should use a router to implement tabbing. But as far as i can see routers act on application level and are intended to be used in single UI-compos.
The problem is in your template:
<li {{action "{{this.actionName}}" target="{{this.value}}"}} >{{this.title}}</li>
AFAIK, actions can't be bound, so when you write this, it tries to call the method {{this.actionName}} instead of firstTab, for example.
I think this is a typical example where you should use a Ember.CollectionView with an itemViewClass which has the click method, i.e.:
App.MyCollectionView = Ember.CollectionView.extend({
tagName: 'ul',
templateName: 'the-template-name',
itemViewClass: Ember.View.extend({
click: function() {
var actionName = this.get('content.actionName'),
target = this.get('controller.target');
target.send(actionName);
}
})
});
The code above is surely not right, but the idea is here.
But I think the Router is the right way to do that. I suggest you to take a look at the Ember Router example by #ghempton, where it defines tab with Ember.Router.
You have 2 options:
1) each tabpage has its own controller, view and must also be defined in the router
<script type="text/x-handlebars" data-template-name="tabs">
<div>
<ul class="nav nav-tabs">
{{#view Bootstrap.TabItem item="info"}}
<a {{action gotoInfo}}>Info</a>
{{/view}}
{{#view Bootstrap.TabItem item="anamnese"}}
<a {{action gotoAnamnese}}>Anamnese</a>
{{/view}}
{{#view Bootstrap.TabItem item="medication"}}
<a {{action gotoMedication}}>Medication</a>
{{/view}}
</ul>
{{outlet}}
</div>
</script>
Bootstrap.TabItem = Ember.View.extend({
tagName: 'li',
classNameBindings: ['isActive:active'],
isActive: function() {
return this.get('item') === this.get('controller.selectedTab');
}.property('item', 'controller.selectedTab').cacheable()
});
2) all tabpages are in one large view, and tabpages will be hidden or shown
{{#view Ember.TabContainerView currentView="info"}}
<ul class="nav nav-tabs">
{{#view Bootstrap.TabView value="info"}}<a>Info</a>{{/view}}
{{#view Bootstrap.TabView value="anamnese"}}<a>Anamnese</a>{{/view}}
{{#view Bootstrap.TabView value="medication"}}<a>Medication</a>{{/view}}
</ul>
{{#view Ember.TabPaneView viewName="info"}}
{{view EEPD.InfoView}}
{{/view}}
{{#view Ember.TabPaneView viewName="anamnese"}}
{{view EEPD.AnamneseView}}
{{/view}}
{{#view Ember.TabPaneView viewName="medication"}}
{{view EEPD.MedicationView}}
{{/view}}
{{/view}}
Bootstrap.TabView = Ember.TabView.extend({
tagName: 'li',
classNameBindings: ['isActive:active'],
isActive: function() {
return this.get('value') === this.get('tabsContainer.currentView');
}.property('tabsContainer.currentView').cacheable()
});
There are two ways to implement a tab panel.
If you want your tabs to be bookmarkable, then you should implement them using Router:
Templates
<script type="text/x-handlebars" data-template-name="application">
<div class="tabpanel">
<div class="tabs">
<div {{action "goToFirstTab"}}>First tab</div>
<div {{action "goToSecondTab"}}>Second tab</div>
</div>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="firstTab">
First Tab content
</script>
<script type="text/x-handlebars" data-template-name="secondTab">
Second Tab content
</script>
Code:
var App = Ember.Application.create();
App.ApplicationController = Ember.Controller.extend();
App.ApplicationView = Ember.View.extend();
App.FirstTabView = Ember.View.extend({templateName: "firstTab"});
App.FirstTabController = Ember.Controller.extend();
App.SecondTabView = Ember.View.extend({templateName: "secondTab"});
App.SecondTabController = Ember.Controller.extend();
App.Router = Ember.Router.create({
root: Ember.Route.extend({
goToFirstTab: Ember.Route.transitionTo("firstTab"),
goToSecondTab: Ember.Route.transitionTo("secondTab"),
index: Ember.Route.extend({
route: "/",
redirectsTo: "firstTab"
}),
firstTab: Ember.Route.extend({
route: "/firstTab",
connectOutlets: function (router) {
router.get('applicationController').connectOutlet('firstTab');
}
}),
secondTab: Ember.Route.extend({
route: "/secondTab",
connectOutlets: function (router) {
router.get('applicationController').connectOutlet('secondTab');
}
})
})
});
App.initialize(App.Router);
The second way, without Router.
Templates (note that actions` targets are changed)
<script type="text/x-handlebars" data-template-name="application">
<div class="tabpanel">
<div class="tabs">
<div {{action "goToFirstTab" target="controller"}}>First tab</div>
<div {{action "goToSecondTab" target="controller"}}>Second tab</div>
</div>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="firstTab">
First Tab content
</script>
<script type="text/x-handlebars" data-template-name="secondTab">
Second Tab content
</script>
Code (pretty much the same, except that the code related to tabs is now moved to ApplicationController.
var App = Ember.Application.create();
App.ApplicationView = Ember.View.extend();
App.Router = Ember.Route.create();
App.FirstTabView = Ember.View.extend({templateName: "firstTab"});
App.FirstTabController = Ember.Controller.extend();
App.SecondTabView = Ember.View.extend({templateName: "secondTab"});
App.SecondTabController = Ember.Controller.extend();
App.ApplicationController = Ember.Controller.extend({
view: App.FirstTabView.create(),
goToFirstTab: function () {
this.connectOutlet("firstTab");
},
goToSecondTab: function () {
this.connectOutlet("secondTab");
}
});
App.initialize(App.Router);