AngularJS code data-binding through function is not working [duplicate] - angularjs

This question already has answers here:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
(3 answers)
Closed 3 years ago.
When I click the button, default/init values are appended into the textArea but when I try to change the text (firstName/ middleName / lastName) in their respective field, clicking the button has no effect.
Associated code is spread across the following files: MainHTML, cashierApp.html, cashier.js, cashierCtrl.ctrl.js, cashierService.service.js and headTemplate.html
Main HTML page
<html ng-app="cashierAPP">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<title>Cashier-HomePage</title>
<link href="header.css" rel="stylesheet">
<link href="pageTemplate.css" rel="stylesheet">
</head>
<body ng-controller="cashierController">
<ng-include src="'CashierApp.html'"></ng-include>
<script src="http://127.0.0.1:8887/cashier.js"></script>
<script src="http://127.0.0.1:8887/cashierCtrl.ctrl.js"></script>
<script src="http://127.0.0.1:8887/cashierService.service.js"></script>
</body>
</html>
CashierApp.html
<div>
<div>
<ng-include src="'http://127.0.0.1:8887/headtemplate.htm'"></ng-include>
</div>
<div>
<h4>Enter First name</h4><input type="text" ng-model="firstName"><br>
<h4><input type="checkbox" ng-model="hasMiddle">Enter Middle name</h4>
<input type="text" ng-show="hasMiddle" ng-model="middleName"><br>
<h4>Enter last name</h4><input type="text" ng-model="lastName"><br><br>
<button ng-click="getName()">Get Name</button><br>
<h4> Your Full Name: &nbsp &nbsp <textarea ng-bind="fullName" readonly></textarea> </h4>
</div>
</div>
Cashier.js--
var cashierApp = angular.module("cashierAPP",[]);
CashierCtrl.ctrl.js
cashierApp.controller("cashierController", function($scope, cashierService) {
$scope.firstName = "John";
$scope.middleName = "0";
$scope.lastName = "Doe";
$scope.getName = function() {
$scope.fullName = cashierService.NameIs($scope.firstName, $scope.middleName, $scope.lastName);
}
});
CashierService.service.js
cashierApp.service("cashierService", function() {
this.NameIs = function(a, b, c) {
return a + " " + b + " " + c;
}
});
headTemplate.html
<table cellspacing="50px" ; cellpaddinging="20px">
<tr>
<th>AngularJS Cashier Application</th>
<th>This is my Global Nav item 2 </th>
<th>This is my Global Nav item 3 </th>
<th>Participant</th>
</tr>
<tr>
<td>HOME</td>
<td>ABOUT</td>
<td>CALCULATIONS</td>
<td>MORE...</td>
</tr>
<tr class="pageBody">
<td>Put Widgets here...</td>
</tr>
</table>

Since you are using ng-include it will create a separate child scope. So ng-model is not getting updated.
You need to use $parent to access the ng-model properties like below.
<div>
<div>
<ng-include src="'http://127.0.0.1:8080/headtemplate.htm'"></ng-include>
</div>
<div>
<h4>Enter First name</h4><input type="text" ng-model="$parent.firstName"><br>
<h4><input type="checkbox" ng-model="hasMiddle">Enter Middle name</h4>
<input type="text" ng-show="hasMiddle" ng-model="$parent.middleName"><br>
<h4>Enter last name</h4><input type="text" ng-model="$parent.lastName"><br><br>
<button ng-click="getName()">Get Name</button><br>
<h4> Your Full Name: &nbsp &nbsp <textarea ng-model="fullName" readonly></textarea> </h4>
</div>
</div>

Related

Writing an adding function in AngularJS

I'm new to AngularJS and I am doing some tutorials to get in touch with it. While I'm doing the tutorials I have modified the code a bit to get a better feeling of what's behind. My code consists of two parts, which have nothing to do with each other.
The first one is a simple user input and based on that a list gets filtered. This is working fine.
However, in the second part I was trying to implement a simple adding function where the user can give an input and based on that the sum of two numbers is calculated. This part is not working at all. The numbers are being recognised as strings. The code is basically from this source here. When I copy the whole code and run it, it works fine, but when I modify it a bit it doesn't.
I want to understand why my code isn't working. To me there is nearly no difference. So I think that I eventually misunderstood the concept of angularjs. But I can't figure out where the error could be.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script type="text/javascript">
function TodoCtrl($scope) {
$scope.total = function () {
return $scope.x + $scope.y;
};
}
</script>
</head>
<body data-ng-app>
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</body>
</html>
Several things to change...
First you need to create a module:
var app = angular.module("myApp", []);
Then you need to define a module e.g. myApp on the ng-app directive.
<body data-ng-app="myApp">
Then you need to add TodoCtrl to the module:
app.controller("TodoCtrl", TodoCtrl);
Also check that both $scope.x and $scope.y have values, and make sure that they are both parsed as integers, otherwise you will get string concatenation ("1"+"1"="11") instead of addition (1+1=2)!
$scope.total = function () {
return ($scope.x && $scope.y)
? parseInt($scope.x) + parseInt($scope.y)
: 0;
};
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script type="text/javascript">
(function(){
var app = angular.module("myApp", []);
app.controller("TodoCtrl", TodoCtrl);
function TodoCtrl($scope) {
$scope.total = function () {
return ($scope.x && $scope.y)
? parseInt($scope.x) + parseInt($scope.y)
: 0;
};
}
}());
</script>
</head>
<body data-ng-app="myApp">
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</body>
</html>
As mentioned in the above two answers adding TodoCtrl as controller instead function will make the snippet work.
REASON:
Angularjs framework above 1.3 does not support global function which means declaring controller as function wont work.
In your code snippet, you are using angular version 1.5, which needs the controller to be defined.
DEMO
angular.module("app",[])
.controller("TodoCtrl",function($scope){
$scope.x = 0;
$scope.y = 0;
$scope.total = function () {
return parseInt($scope.x) + parseInt($scope.y)
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" >
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</div>
you need to define the TodoCtrl as controller instead function
.controller("TodoCtrl",function($scope){
$scope.x = 0;
$scope.y = 0;
$scope.total = function () {
return parseInt($scope.x) + parseInt($scope.y)
};
})
Demo
angular.module("app",[])
.controller("TodoCtrl",function($scope){
$scope.x = 0;
$scope.y = 0;
$scope.total = function () {
return parseInt($scope.x) + parseInt($scope.y)
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" >
<input type="text" ng-model="name">{{name}}
<div data-ng-init="Names=['Arthur', 'Bob', 'Chris', 'David', 'EDGAR']">
<ul>
<li data-ng-repeat="naming in Names | filter: name ">{{naming}}</li>
</ul>
</div>
<div data-ng-controller="TodoCtrl">
<form>
<input type="text" ng-model ="x">{{x}}
<input type="text" ng-model ="y"> {{y}}
<input type="text" value="{{total()}}"/>
<p type= "text" value="{{total()}}">value</p>
</form>
</div>
</div>

Angular Wiring up two controllers from Model to auto fill form

I've got an angular app I'm working on where I'm trying to auto fill a pop up modal based on a user's selection.
I thought I could use my model service to keep track of what the user selected and 'wire' the controller for the <select> list and it's edit button to the model but that doesn't seem to work.
Adding to the complexity I'm using angular-route and my <select> list is buried in a view. I was trying to keep my pop up modals in a separate controller outside the view because they've got their own templates and I had problems when I nested them into the view...
I've seen a few examples of wiring up angular apps and thought I understood them but I can't figure out what I'm doing wrong.
EDIT (thanks Pankaj Parkar for pointed out my mistakes in the plunker):
I have a plunker here:
https://plnkr.co/edit/6f9FZmV8Ul6LZDm9rcg9?p=preview
Below is the snipped in a single HTML page with CDN links :).
Am I just completely misunderstanding how angularjs is suppose to work?
<html ng-app="myApp">
<head>
<title>Bootstrap 3</title>
</head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<body>
<div ng-view></div>
<script id="editables.html" type="text/ng-template">
<div class="container">
<div class="jumbotron">
<form>
<div class="form-group">
<select class="form-control" id="mapsSelect" size="10" multiple ng-model="model.selected">
<option ng-repeat="n in editables">{{n}}</option>
<select>
</div>
<a href="#editModal" class = "btn btn-info" data-toggle="modal" ng-click="edit()" >Edit</a>
</form>
</div>
</div><!--end container div-->
</script>
<div ng-controller="modalsController">
<div id="editModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<form class="form-horizontal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4>New Map</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="name" class="col-lg-3 control-label">Name</label>
<div class="col-lg-9">
<input type="text" class="form-control" id="name" ng-model="formModel.name"></input>
</div>
</div>
<div class="form-group">
<label for="desc" class="col-lg-3 control-label">Description</label>
<div class="col-lg-9">
<input type="text" class="form-control" id="desc" ng-model="formModel.desc"></input>
</div>
</div>
<div class="modal-footer">
<pre> {{ formModel | json }}<br><br>Working: {{ workingMap }}</pre>
Cancel
Continue
</div>
</form>
</div>
</div>
</div><!-- end modal -->
</div>
</body>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular-route.min.js"></script>
<script src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- <script src = "js/script.js"></script> -->
<script>
var app = angular.module('myApp', ['ngRoute']);
var modelService = function ($log){
var moduleHello = function(myMessage){
console.log("Module hellow from myService " + myMessage);
}
var moduleNames = {
"First" : {desc: "First's Description"},
"Second" : {desc: "Second's Description"},
"Third" : {desc: "Third's Description"}
};
var moduleWorkingName = {};
return {
hello: moduleHello,
editables: moduleNames,
workingName: moduleWorkingName
}
}//end modelService
app.factory("modelService", ["$log", modelService]);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/editables', {
controller: "editablesController",
templateUrl: "editables.html"
}).
otherwise({
redirectTo: "/editables"
});
}]);
app.controller('editablesController', ['$scope', '$log','modelService', function($scope,$log, $modelService) {
$scope.model = {};
//console.log( JSON.stringify( $modelService.editables ) );
$scope.editables = [];
for ( name in $modelService.editables){
$scope.editables.push( name );
}
$scope.edit = function(){
if ( typeof $modelService.editables [$scope.model.selected] != 'undefined'){
$modelService.workingName = $modelService.editables [$scope.model.selected];
console.log ("Setting my working name to " + JSON.stringify( $modelService.workingName ) );
}else{
console.log ("Nothing Selected");
}
}
}]);
app.controller('modalsController', ['$scope','modelService', function($scope,$modelService) {
$scope.formModel = {};
$scope.formModel.name = "Hard coding works of course";
$scope.formModel.desc = $modelService.workingName.desc; //But I can't seem to get this to update. I thought pointing it at an object in the Model would be enough.
console.log("Firing up modalsController");
}]);
</script>
</html>
I spent the last two days mulling over this in my head and I think I figured it out. For starters, here's the (working) plunker:
https://plnkr.co/edit/Kt3rebPtvGTt0WMXkQW4?p=preview
Now, the explanation. I was trying to keep a separate 'formModel' object that kept track of the controller's state. But that's both silly and pointless.
Instead what you're supposed to do is:
a. Create an object in your service to hold all your data (I just called this 'model')
b. For each controller that needs to share data create a variable on the $scope of the controller and point it to your 'model' variable from your service.
c. after that use the variables from your model in your html.
So in both my controllers you'll find this line:
$scope.model = $modelService.model;
and in my HTML you'll find stuff like this:
<input type="text" class="form-control" id="name" ng-model="model.workingName.name"></input>
notice how I'm using "model.workingName.name"? This references $scope.model.workingName.name, which thanks to the line $scope.model = $modelService.model from my JavaScript now points directly to my model.
And that is how you "wire up" Angular.
By the way, experienced Angular folks have probably noticed that this part:
$scope.editables = [];
for ( name in $modelService.model.names){
$scope.editables.push( name );
}
probably belongs in a directive instead of a controller because I'm editing the DOM.
Stuff like that's what makes it so hard to learn AngularJS. There's so many concepts to get the hang of.

AngularJS app go back to inital state automatically

Following app shows three todo items at first and
after adding an new data, it shows updated lists for a moment and go back to the original state.
Could you tell me why does it go back to the initial state automatically?
link for Pluker
http://plnkr.co/edit/h6THusBe7AWFle5ixXzX?p=preview
==================================
<!DOCTYPE html>
<html ng-app="initExample">
<head>
<link data-require="bootstrap-css#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.4.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body class="well" ng-controller="ExampleController">
<h1> AngularJS Todo List</h1>
<p> Total <strong> {{todolist.length}} </strong> / Remain <strong> {{countRemain()}} </strong> </p>
<ul>
<li ng-repeat="todo in todolist" class="checkbox"> <input ng-model="todo.done" type="checkbox"> {{todo.title}}</li>
</ul>
<form name="newItemForm" class="form-inline" action="">
<div class="form-group">
<label class="sr-only" for="newItemText" placeholder="Type new ToDo"></label>
<input type="text" class="form-control" ng-model="newTodo" name="newItemText" placeholder="Type new Todo">
</div>
<button type="submit" ng-click="addNewTodo(newTodo)" class="btn btn-default"> Add </button>
</form>
</body>
</html>
============================
// Code goes here
var mymodule=angular.module('initExample', []);
mymodule.controller('ExampleController',
['$scope', function($scope) {
$scope.todolist = [
{done: true, title:'AngularJS study'},
{done: false, title:'music listening'},
{done: false, title:'run'}
];
$scope.countRemain = function() {
var count = 0;
var list = $scope.todolist;
angular.forEach(list, function(val, key) {
if(!list[key].done) count++;
});
return count;
};
$scope.addNewTodo = function(newTodo) {
todolist.push({done: false, title: newTodo});
};
}
]
);
Remove the action attribute from the form or add "preventDefault" from the button click.
Fixed the plunkr:
<form name="newItemForm" class="form-inline">
http://plnkr.co/edit/KFpbbdlDPbnIPAW43EaG?p=preview
P.S. also fixed the addNewTodo Function:
$scope.addNewTodo = function(newTodo) {
$scope.todolist.push({done: false, title: newTodo});
};
You need to remove action attribute from form definition, otherwise browser will try to submit it, reloading the page:
<form name="newItemForm" class="form-inline">
<!-- ... -->
</form>
Demo: http://plnkr.co/edit/MwTmGqzdELzUbrY82kKg?p=preview

Uncheck checkbox with submit - AngularJS

I am trying to uncheck checkbox with submit button. The idea is when checkbox is checked button is shown, and when button is clicked checkbox is unchecked and button is hidden.
HTML page:
<html ng-app="myApp" ng-controller="myCtrl">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="script.js"></script>
<meta charset=utf-8 />
</head>
<body>
<div ng-repeat="foo in boxes">
<div>
<input type="checkbox" name="cb" id="cb" ng-model="show" />{{foo}}
</div>
<div ng-show="show">
<form ng-submit="submit()">
<input type="submit" name="sumbit" id="sumbit" value="Hide" />
</form>
</div>
</div>
</body>
</html>
JS:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.boxes = ['a','b','c'];
$scope.submit = function(){
$scope.show = false;
}
});
On Plukner: http://plnkr.co/edit/z9W0w18dkgYJ3D5Q3aR2?p=preview
Thanks for any help!
The problem is that you're using a single variable to store states of 3 items yet Angular creates a scope for each context in the ng-repeat iteration. By changing show to an array and using $index to reference each of them, the show array from the main scope is passed to all three child scopes and there are no conflicts, so it works:
app.controller('myCtrl', function($scope) {
$scope.boxes = ['a','b','c'];
$scope.show = [];
$scope.submit = function(){
$scope.show = [];
}
});
HTML
<div ng-repeat="foo in boxes">
<div>
<input type="checkbox" name="cb" id="cb" ng-model="show[$index]" />{{foo}}
</div>
<div ng-show="show[$index]">
<form ng-submit="submit()">
<input type="submit" name="sumbit" id="sumbit" value="Hide" />
</form>
</div>
</div>
See it here: http://plnkr.co/edit/kfTMaLTXWtpt7N9JVHAQ?p=preview
(note sure if this is exactly what you wanted because there's no question, but it's enough to get you started)
UPDATE
And here is the version where Hide unchecks only "its own" checkbox ($scope.submit now accepts the index parameter): http://plnkr.co/edit/YVICOmQrPeCCUKP2tBBl?p=preview
You need to change the html code and simplify it as
Instead of form use simple ng-click
<div ng-show="show">
<input type="submit" value="Hide" ng-click="show = !show" />
</div>

Edit functionality in ng-controller

I am trying to display a list of objects from a controller and then trying to edit them.
I am binding data called editContact to value in input text box. I want to set a variable ii in scope and then when editing is done, then replace contacts[ii] with the temporary object editContact. But ii is not being recognized. Can I set a variable like ii?
<!doctype html>
<html ng-app>
<head>
<style>
</style>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js"></script>
</head>
<body>
<div ng-controller="contactsController">
<label>Name</label>
<input ng-model="name" type="text" placeholder="Name">
<label>email</label>
<input ng-model="email" type="text" placeholder="Email">
<button ng-click="addContact()">Add contact</button>
<div>{{contactsController.name}}</div>
<div>
<ul>
<li ng-repeat="contact in contacts">
<div>{{contact.name}}</div>
<div>{{contact.email}}</div>
<div><button ng-click="deleteContact($index)">delete</button></div>
<div><button ng-click="editContact($index)">Edit</button></div>
</li>
</ul>
<input type="text" value="{{editContact.name}}"/>
<input type="text" value="{{editContact.email}}"/>
<button ng-click="changeValue(ii)">Edit</button>
</div>
</div>
<script>
// Your code goes here.
// $( document ).ready(function() {
// alert('jQuery asdfas!');
// Your code here.
// });
function contactsController($scope){
$scope.contacts=[{name:'asdf',email:'asdf'},
{name:'yweuir',email:'xcvzx'}
];
contactsController.prototype.addContact =function(){
console.log(this.name);
console.log(this.email);
this.contacts.push({name:this.name,email:this.email});
}
$scope.changeValue=function(){
$scope.contacts[$scope.ii]=$scope.editContact;
}
$scope.editContact=function(i){
$scope.editContact=$scope.contacts[i]
$scope.ii=i;
}
}
</script>
</body>
</html>
First, in the DOM always bind attributes for input boxes with ngModel. Example:
<input type="text" ng-model="editContact.name"/>
Second, never use $index as a point of reference for finding things in your controller. You should use the object itself. Example:
<li ng-repeat="contact in contacts">
<button ng-click="editSomeContact(contact)"></button>
</li>
Then your JavaScript should look like this:
$scope.addContact = function() {
$scope.contacts.push({name: '', email: ''});
};
$scope.editSomeContact = function(contact) {
$scope.editContact = contact;
};
$scope.deleteContact = function(contact) {
var index = $scope.contacts.indexOf(contact);
if(index > -1) {
$scope.contacts.splice(index, 1);
}
if($scope.editContact === contact){
$scope.editContact = null;
}
};
At this point, you don't need a changeValue function because you'll see that the contacts in the list will update with the edited fields due to the fact that the values are dynamically bound in both places.

Resources