angularjs multiple controllers on one page - javascript

I have a page with multiple controllers, one of the controller is being used in 2 different divs within the same page. I am not sure if it is a scope issue or I just miss something in my code.
here is the plunkr
http://plnkr.co/edit/IowesXE3ag6xOYfB6KrN?p=preview
I want to hide the textbox when the user clicks on 'Savings' link, display the box when clicking on 'Cost' link.

Same controller, but declared twice. therefor - two scopes.
Normally the solution is to move the ng-controller declaration one dom level higher (in your case, to the body element. once only), and have it only once. Otherwise, look into angular services.
see updated plunkr: http://plnkr.co/edit/pWnx2mdMeOeH33LUeTGm?p=preview

Every time you use ng-controller, you make a new instance of said controller, with it's own scope. If you set subCCtrl on the body tag (or a new parent), and remove it from the two divs it is currently on, it works for me.
Other solutions you might want to look in to are by keeping "hideThisBox" on the root scope, broadcasting an event when clicking on save or by keeping it in a service.

You need to make some changes in controller and view.
var app = angular.module('plunker', []);
app.controller('subCCtrl', function($scope) {
$scope.hideThisBox = false;
$scope.update = function(label) {
if (label == 'Cost')
$scope.displaybox = true;
else
$scope.displaybox = false;
}
});
app.controller('subACtrl', function($scope) {
});
app.controller('subBCtrl', function($scope) {
});
HTML :
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script data-require="angular.js#1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js" data-semver="1.0.8"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="subCCtrl" class="row-fluid">
<div class="span6">
<a href="#" ng-click='update("Cost");displaybox=true;'>Cost</a>
<br />
<a href="#" ng-click='update("Savings");displaybox=fasle;'>Savings</a>
<br />
</div>
<hr />
<div ng-controller="subACtrl">Do stuff that uses subACtrl</div>
<div ng-controller="subBCtrl">Do stuff that uses subBCtrl</div>
<hr />
<div ng-controller="subCCtrl" class="row-fluid">
<div class="span3">
<label>If click on 'Savings', hide below box: </label>
</div>
<div ng-hide="hideThisBox" class="span6">
<input type="text" ng-model="test2" ng-show="displaybox"/>
</div>
</div>
</div>
</body>
</html>

I would recommend that you read up on Javascript scope. The issue with your code was the scope of ng-controllers.

You already got your answer i guess, but for those who will come next here is some tips ^^ (hope it will hep):
ng-controller="myCtrl"
will set a new instance of the "myCtrl" controller, with i'ts own scope
The used scope will be the one of the firt div's controller it means that if you have something like:
<div id="maindiv" ng-controller="myCtrl>
<div id="subdiv1">
<div></div>
<div>
<div>some text</div>
</div>
</div>
<div id="subdiv2" ng-controller="myCtrl">
<div>
<span>-</span>
<span>so</span>
<span>this</span>
<span>is</span>
<span>a</span>
<span>subdiv</span>
<span>.</span>
</div>
</div>
</div>
</div>
Subdiv1 will have the same scope as maindiv
But Subdiv2 will have it's own instance of the myCtrl controller's scope.
In a global way, Subdiv2's scope should have erited is data from the maindiv's scope.
Thats just a few easy tips and you will find more usefull ones on SO, or google, but anyway, if it can help some of you it will be cool.

Related

Unable to pass form data using Angular.js

I am new to Angular.js and am trying to send form data to the server but I am getting an error for angular.js:13424 Error: [ng:areq]. I did try many answers available on Stack Overflow but I am not able to find the answer for my problem.
index.view.html (for register)
<div class="col-md-6 col-md-offset-3" >
<input type="text" ng-model="fname" placeholder="Enter the name :"required >Fristname
<br> <br>
button type="button" class="btn btn-success navbar-btn" ng-click=register()>Register </button>
</div>
index.controller.js
(function ()
{
angular
.module('app')
.controller('register.IndexController', function($scope,$http)
{
$scope.register= function()
{
$http.post('http://localhost:9000/user/register', {firstName : $scope.fname}).success(function(response)
{ console.log($scope.fname);
})
}
})
});
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>AngularJS JWT Authentication Example & Tutorial</title>
<!-- bootstrap css -->
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<!-- application css -->
<link href="app-content/app.css" rel="stylesheet" />
</head>
<!-- HEADER AND NAVBAR -->
<header>
<nav class="navbar navbar-default">
<nav class="cf" ng-include="'nav/index.view.html'" ng-controller="Main.IndexController"></nav>
</nav>
</header>
Seems that you are using the wrong controller identifier while processing your request.
You have named your controller as register.IndexController, but from the html , you are trying to access it as Main.IndexController.
Please check whether changing the html controller idenentifier solves your problem.
If you plan on using nested controllers, you can do that also. But the scope has to be identified correctly whichever controller you are using.

How do I change a ng-src on another img with ng-click?

*I updated the plunkr and the code to better represent my localhost version. The Angularjs version was not the problem despite fixing the previous plunkr. *
First, let me say I am really struggling with Angularjs but I'm determined to learn it. I'm a designer, not a brick-layer (forgive the Star Trek reference).
I'm building a prototype where clicking on a small thumbnail to the left loads a larger version to the right. I'm using ng-click on the image to pass the unique "current" ID. Clicking doesn't affect the large image ng-src. I tried various permutations and don't see what I could be doing wrong.
*New info: I am using ng-repeat to iterate through a list of images. I try to pass each image url through ng-click but that seems to be where it gets lost. *
http://plnkr.co/edit/vYiykI7dfMKd34ZmS13N?p=preview
The app/controller:
<script>
var app = angular.module('pageApp', []);
app.controller('imgCtrl', function($scope) {
$scope.current = '7078/7250439172_72562c8e45_k';
});
</script>
The html wth thumbnail and large image:
<div class="container">
<div class="row" ng-app="pageApp" ng-controller="imgCtrl">
<div class="col-xs-3">
<ul class="list-group sm-img">
<li class="list-group-item text-center" ng-repeat="n in ['7078/7250439172_72562c8e45_k', '7087/7250440014_a32980508e_k', '7225/7250440766_8db45aa277_h']">
<img class="img-responsive" src="https://farm8.staticflickr.com/{{n}}.jpg" ng-click="current='{{n}}'" /><span>{{current}}</span>
</li>
</ul>
</div>
<div class="col-xs-9">
<img class="img-responsive" ng-src="https://farm8.staticflickr.com/{{ current }}.jpg" />
</div>
</div>
</div>
Try to create function in controller an execute it from ng-click
$scope.changeImg = function (c) {
$scope.current=c;
}
Your problem quite funny: you are loading Angular2 version however using Angular1.x syntax and code. Load correct library version, for example 1.4.8, and everything will start working properly:
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
Demo: http://plnkr.co/edit/0efkCT9wwEaWfK0nR6su?p=info
It is working now. http://plnkr.co/edit/nmqDqcmtyTq479wZWsuR?p=preview
you are using angular 2 which has much more different than angular 1 (1.4)
<!DOCTYPE html>
<html ng-app="pageApp">
<head>
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/cosmo/bootstrap.min.css" />
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
<script data-require="bootstrap#3.3.5" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://code.angularjs.org/1.4.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script>
var app = angular.module('pageApp', []);
app.controller('imgCtrl', function($scope) {
$scope.current = '7078/7250439172_72562c8e45_k';
});
</script>
</head>
<body>
<div class="container">
<div class="row" ng-controller="imgCtrl">
<div class="col-xs-3">
<img class="img-responsive" src="https://farm8.staticflickr.com/7078/7250439172_72562c8e45_k.jpg" ng-click="current='7078/7250439172_72562c8e45_k'" />
<img class="img-responsive" src="https://farm8.staticflickr.com/7087/7250440014_a32980508e_k.jpg" ng-click="current='7087/7250440014_a32980508e_k'" />
<img class="img-responsive" src="https://farm8.staticflickr.com/7225/7250440766_8db45aa277_h.jpg" ng-click="current='7225/7250440766_8db45aa277_h'"/>
</div>
<div class="col-xs-9">
<img class="img-responsive" ng-src="https://farm8.staticflickr.com/{{ current }}.jpg" />
</div>
</div>
</div>
</body>
</html>

Nested ViewModels in Knockoutjs 3.2.0

I have a global view model which is applied to main div
and I have some other view models and I want to apply them to nested elements of my main div
but I am getting the
You cannot apply bindings multiple times to the same element.
and here it is a sample :
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<div id="main">
<input data-bind="value:title,valueUpdate:'afterkeyup'" />
<h1 data-bind="text:title"></h1>
<hr />
<div id="sub">
<input data-bind="value:name,valueUpdate:'afterkeyup'" />
<label data-bind="text:name"></label>
<!-- a reference to title in globalViewModel -->
<h1 data-bind="text:title"></h1>
</div>
</div>
<script src="Scripts/knockout-3.2.0.js"></script>
<script>
var globalViewModel = {
title : ko.observable("global title")
}
var subViewModel = {
name : ko.observable("Test")
}
ko.applyBindings(globalViewModel);
ko.applyBindings(subViewModel, document.getElementById('sub'));
</script>
</body>
</html>
Please guide me with your brilliant solutions :)
Need to apply binding separately for both view modal
or can just create both property in same viewModal

Directives in angular js not working properly

I have two directives in my first22 module mycustomer1 and mycustomer. Problem is mycustomer directive is not called ? Can anyone explain me what i am doing wrong here?
Below is my html
<!DOCTYPE html>
<html ng-app="first22">
<head>
<link rel="icon" type="image/png" href="globe/images/correct.png"/>
<link rel="stylesheet" type="text/css" href="globe/css/style.css"/>
<script type="text/javascript" src="globe/script/jquery.js"></script>
<script type="text/javascript" src="globe/script/angular.js"></script>
<script type="text/javascript" src="globe/script/mainscope.js"></script>
<script type="text/javascript" src="globe/script/angular-route.js"></script>
</head>
<body >
<div id="maincontainer" ng-controller="nameListCtrl">
<div id="header">
<div id="headtext">HTML5 SAMPLE</div>
<mycustomer/>
<mycustomer1/>
</div>
<div id="sidebar" >
<first-directive></first-directive>
<ul id="mainmenu" style="">
<li ng-repeat="item1 in content"><a style="color:grey;" id="{{item1.title }}" class="asa" ng-click="show=!show" ng-model="checked" ng-href="#/{{item1.title }}">{{item1.title }}</a>
<ul ng-show="show " ng-if="item1.subitems" style="text-align:left;margin-left:25px;">
<li ng-repeat="category in item1.subitems" >
{{ category.title }}
</li>
</ul>
</li>
</ul>
</div>
<div id="content">
<div id="content_flow" ng-view="">
</div>
</div>
<div id="Interactive_content">
<div id="Interactive_content_flow">
<div id="close">
</div>
</div>
</div>
</div>
</body>
</html>
And my angular directive declaration below
var first2 = angular.module('first22', []);
first2.directive('mycustomer1',function()
{
return{
restrict:'E',
replace: 'true',
template:'<h1>aaaaaaaaaaaaaaaaaaaaaa</h1>',
link: function()
{
alert("I'm working");
}
}
})
first2.directive('mycustomer', function()
{
return {
restrict: "E",
replace: 'true',
template: '<h3>Hello World!!</h3>',
link: function()
{
alert("I'm working 1");
}
}
});
Directive names, when being declared should be in camelCase
first2.directive('myCustomer', function() { ... }
When using them in HTML elements, you must use hyphenated-lower-case
<my-customer></my-customer>
Working jsFiddle Demo
As Rene pointed out above, it is only a convention and it works without the camel case too. Raghav code works because he used empty closing tags like this "" and not ""
The issue is that "mycustomer" directive has replace clause in definitation and self-closing tags work only for a few some kinds of tags, browser doesn't close the "mycustomer" tag at all until the point it's parent, div in this case, closes so "mycustomer1" shows up inside the "mycustomer" tag so when "mycustomer" directive runs, it replaces it content which is now "mycustomer1" and hence "mycustomer1" doesn't actually run at all.
In essence, the code by OP really looks like below so when "mycustomer" runs, it removes "mycustomer1" from the HTML because of the "replace" in mycustomer's directive definition.
<div>
<mycustomer>
<mycustomer1></mycustomer>
</mycustomer>
<div>
The reason Seminda's solution works is again that the individual "mycustomer" and "mycustomer1" are included in parent divs so they close right before the div close themselves.
For directives inside directive, checkout "transclude" property working with replace.
Place your directive in the code like below. then it will work.
<div>
<mycustomer />
</div>
<div>
<mycustomer1 />
</div>
Working demo

Using ng-switch to swap templates

I'm trying to switch a "sign in" form for a "sign up" form whenever the user clicks on the "Sign Up" button in my angular app, but at the moment nothing is happening when the button is clicked; The sign in form remains on the screen and there are no console errors. Can anyone tell me where I'm going wrong?
I'm attempting to do this purely in html, is this even possible to achieve?
EDIT: I included a signup function in my UserCtrl which takes care of signing in/ out. Now when I click on sign up the alert is trigger but I get a console error saying TypeError: boolean is not a function.
$scope.signup = function() {
alert('signup function hit');
$scope.signup = true;
}
EDIT 2:
<!DOCTYPE html>
<html ng-app="myApp" >
<head>
<title> My App</title>
<link rel="stylesheet" type="text/css" href="css/app.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" type="text/css" href="css/signin.css">
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css" rel="stylesheet"/>
</head>
<body ng-controller="MainCtrl">
<div ng-switch on="view.name">
<div ng-switch-default ng-controller="UserCtrl">
<div ng-show="!isAuthenticated">
<form class = "form-signin">
<div class="control-group">
<img src="img/logo.png">
<br />
<div class="controls">
<br />
<input type="text" ng-model="username" placeholder = "Email Address" >
</div>
<br />
<div class="controls">
<input type="password" ng-model="password" placeholder = "Password" >
</div>
<div class="controls">
<button class = "btn btn-default" ng-click="signIn()">Sign In</button>
<button class = "btn btn-primary" ng-click="view.name = 'signup'">Register</button>
</div>
</div>
</form>
</div>
<div ng-switch-when="signup" ng-controller = "UserNewCtrl" >
<label>
This is where my form should be when my signup button is clicked.
</label>
</div>
//This part of index.html is only shown when a user has been authenticated
<div ng-show="isAuthenticated">
<div class="col-md-2">
//MenuBar code is here
</div>
//Other templates get loaded here
<div class="col-md-10">
<div ng-view></div>
</div>
</div>
</div>
<script src="js/vendor.js"></script>
<script src="js/app.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/jquery-1.10.2.js"></script>
<script src="js/transition.js"></script>
<script src="js/ui-utils.js"></script>
</div>
</body>
</html>
MainCtrl.js:
angular.module('myApp.controllers')
.controller('MainCtrl', function($scope) {
$scope.view={
name: ''
};
})
To achieve your requirement you need a wrapper controller that hold ng-switch on model because ngSwitch creates child scope.
You can design your view like
<body ng-controller="mainCtrl">
<div ng-switch on="view.name">
<div ng-switch-default ng-controller="signInCtrl">
<h1>this is sign in page</h1>
sign in
<br>
go to sign up page
</div>
<div ng-switch-when="signup" ng-controller="signUpCtrl">
<h1>this is sign up page</h1>
sign up
<br>
go to sign in page
</div>
</div>
</body>
Here mainCtrl holds view.name and by default ng-switch-default works means your sign in page, then when you click
go to sign up page
view.name model changed and your sign-up page appear.
Check the Demo
move the app controller to the html tag, then the directive in your body tag should read if you want to match an expression
<html ng-app="myApp">
<body ng-switch="signup">
see here
where signup is a boolean in your myApp scope, that will presumably be changed when the signIn criteria is satisfactory
$rootScope.signup = true;
you can also achieve similar with the ng-show and ng-hide directives

Categories

Resources