Cannot get model value in Controller method in Angular js - javascript

I am developing an app in Angular js
javascript:
$scope.spentAmount = function() {
angular.forEach($scope.expenses, function(expense) {
if(expense.done){
console.log($scope.spentamount);
}
});
//return amount;
};
HTML:
<label for="spentby">Spent by</label>
<ul class="unstyled">
<li ng-repeat="expense in expenses">
<input type="checkbox" ng-model="expense.done">
<span>{{expense.text}}</span>
<input type="text" ng-show="expense.done" ng-model="spentamount" size="30"
placeholder="Enter the amount">
</li>
</ul>
<form ng-submit="addExpense()">
<input type="text" ng-model="expenseText" size="30"
placeholder="Enter the names">
<input class="btn-primary" type="submit" value="Add">
</form>
<label for="amountspent">Amount spent(Rs)</label>
<span>{{spentAmount()}}</span><br>
but console.log($scope.spentamount) returns undefined.
But the method gets called
Please Advice

The reason for the 'undefined' is in the async behaviour. Your code is going through the collection of expenses sooner then it is loaded. Check the $watch(watchExpression, listener, objectEquality)
a draft how to observe changing colleciton expenses
// a new variable containing total
$scope.total = 0;
$scope.$watch('expenses', function (exps) {
angular.forEach(exps, function (exp) {
if(exp.done){
// here should/must be your calculation
$scope.total + exp.Amount;
}
});
});
now we can adjust the template and consume the up-to-date result
<!--<span>{{spentAmount()}}</span><br>-->
<span>{{total}}</span><br>
Also think about introducing something like $scope.myModel = { expenses : [], total : 0 }... Because:
if you use ng-model there has to be a dot somewhere. If you don't have a dot, you're doing it wrong...

While binding inside the ng-repeat you need to use $parent to use parent scope, like-
<li ng-repeat="expense in expenses">
<input type="checkbox" ng-model="expense.done">
<span>{{expense.text}}</span>
<input type="text" ng-show="expense.done" ng-model="$parent.spentamount" size="30"
placeholder="Enter the amount" />
</li>

Related

Angular 4 - using ngModel inside (click)

So I have the following html:
<div class="workflow-row">
<input type="checkbox" id="new-workflow" [(ngModel)]="new_checkbox">
<label>New Workflow</label>
<input type="text" *ngIf="new_checkbox" placeholder="Enter Workflow Name">
</div>
<div class="workflow-row">
<input type="checkbox" id="edit-workflow" [(ngModel)]="edit_checkbox">
<label>Edit Workflow</label>
<select *ngIf="edit_checkbox"></select>
</div>
I want the checkboxes to act like radio buttons, ie: if one is checked, the other one becomes unchecked with angular 4. I tried doing
<input type="checkbox" id="edit-workflow" (click)="new_checkbox.checked = false"
[(ngModel)]="edit_checkbox">
but I get an error and it says that new_checkbox is undefined. The weird thing is that new_checkbox and edit_checkbox work inside the ngIf statements but not inside the (click)'s. What am I doing wrong?
I suggest you to try the following:
component.ts:
export class AppComponent {
edit_checkbox = false;
new_checkbox = true;
dropNewValue() {
this.new_checkbox = false;
}
dropEditValue() {
this.edit_checkbox = false;
}
}
Then in your template file, e.g. component.html, change your template slightly to:
<div class="workflow-row">
<input type="checkbox" id="new-workflow" [(ngModel)]="new_checkbox" (ngModelChange)="dropEditValue()">
<label>New Workflow</label>
<input type="text" *ngIf="new_checkbox" placeholder="Enter Workflow Name">
</div>
<div class="workflow-row">
<input type="checkbox" id="edit-workflow" [(ngModel)]="edit_checkbox" (ngModelChange)="dropNewValue()">
<label>Edit Workflow</label>
<select *ngIf="edit_checkbox"></select>
</div>
I've just tried this and it works. However I do recommend to switch to radio buttons approach, because you will get the same behavior out of the box.
Don't write Angular like you're writing regular javascript instead of
(click)="new_checkbox.checked = false"
do something like
// .html
(click)="uncheckNewCheckbox()"
// .js or .ts
uncheckNewCheckbox() {
this.new_checkbox.checked = false;
}

How To Get Dynamic Child Value Inside Dynamic Parent (DIV) While Loop

I have question regarding dynamic object HTML where I think it's complicated. I need to read value of children object where it's dynamic inside parent div also dynamic.
It's so hard to me to find a right script where I can read children object value accordingly and keep as a group data before post to server.
Let me show you an example of my script below same as appear on firefox firebug:-
<div id="divtrans[]" class="purchase-items">
<input type="button" name="tripno[]" value="PB" class="field btn-field">
<input type="text" name="busno[]" value="XX001" class="field txt-field">
<input type="text" name="amount[]" value="500" class="field txt-field">
<input type="button" id="btnhideshowdiv" class="hideshow-div btn-remove" style="border:solid">
<div id="comission" style="margin-left:25px;background-color:antiquewhite">
<label style="float:left; margin-right:100px;">Commision</label><label>Amount</label>
<ul>
<li>
Advance
<input type="text" name="txtadvance[]" value="60" />
</li>
<li>
Pay Trip
<input type="text" name="txtpaytrip[]" value="60" />
</li>
</ul>
</div>
<div id="divexpeses" style="margin-left:25px;background-color:antiquewhite">
<label style="float:left; margin-right:100px;">Expenses</label><label>Amount</label>
<ul>
<li>
Advance
<input type="text" name="txtpetrol[]" value="70" />
</li>
<li>
Pay Trip
<input type="text" name="txtticket[]" value="70" />
</li>
</ul>
</div>
</div>
<div id="divtrans[]" class="purchase-items">
<input type="button" name="tripno[]" value="PB" class="field btn-field">
<input type="text" name="busno[]" value="XX002" class="field txt-field">
<input type="text" name="amount[]" value="1000" class="field txt-field">
<input type="button" id="btnhideshowdiv" class="hideshow-div btn-remove" style="border:solid">
<div id="comission" style="margin-left:25px;background-color:antiquewhite">
<label style="float:left; margin-right:100px;">Commision</label><label>Amount</label>
<ul>
<li>
Advance
<input type="text" name="txtadvance[]" value="80" />
</li>
<li>
Pay Trip
<input type="text" name="txtpaytrip[]" value="80" />
</li>
</ul>
</div>
<div id="divexpeses" style="margin-left:25px;background-color:antiquewhite">
<label style="float:left; margin-right:100px;">Expenses</label><label>Amount</label>
<ul>
<li>
Advance
<input type="text" name="txtpetrol[]" value="90" />
</li>
<li>
Pay Trip
<input type="text" name="txtticket[]" value="90" />
</li>
</ul>
</div>
</div>
As you can see I have 2 divtrans[] as parent where each parent have:-
tripno[]
busno[]
amount[]
then have a 2 div with children also
divcommision[]
txtadvance[]
txtpay[]
divexpenses[]
txtpetrol[]
txtticket[]
All this have value and I need to collect all value and write like below as string:-
parent1/PB,XXX001,500/60,60/70,70
parent2/PB,XXX002,1000/80,80/90,90
What I already done on my function like this below where still not working regarding read children value while loop:-
function readparentchildelement() {
var tdivtrans=0;
var dt
tdivtrans= $('div.purchase-items').length
for (start = 0; start < tdivtrans ; start++) {
//$.each($('div.purchase-items').parents(), function (index, value) {
//read parent div one by one
alert($('.purchase-items').index(start));
dt="parent" & start &"/"
var ch
//then read tripno[] busno[] amount[]
ch=$('.purchase-items').index(start).($('tripno')[start]).val());
ch= ch & "," & $('.purchase-items').index(start).($('busno')[start]).val());
ch= ch & $('.purchase-items').index(start).($('busno')[start]).val()) & "/";
alert(ch);
var chDiv1
//read child inside divcommison
var chDiv2
//read child inside divexpenses
//--loop ++ read next children
//});
}
$("#txtMyValue").Val(pr & ch & chDiv1 & chDiv2);
}
I don't know what a right syntax to make it run, please help me.
One correction to your html. It is not recommended to have two elements with same id. So, I would really suggest you to make comission and divexpeses have classes with these names and not as ids. This will make your life much easy.
I was unable to understand how you construct the string you are requesting, hence I've created a dummy object and I'm printing it all to the console. Here is the link to to the fiddle (https://jsfiddle.net/sniper6/9L9of9yj/). I've modified the HTML to have comission and divexpese as classes. Just open the dev tools and check out the console. It reads something like this:
parent 1
tripno -> PB
busno -> XX001
amount -> 500
txtadvance -> 60
txtpaytrip -> 60
txtpetrol -> 70
txtticket -> 70
--------------------
parent 2
tripno -> PB
busno -> XX002
amount -> 1000
txtadvance -> 80
txtpaytrip -> 80
txtpetrol -> 90
txtticket -> 90
--------------------

Set ng-model value to button click

I have this little snippet of code to set the root.lowWeight and root.highWeight to my controller.
<input type="number" placeholder="Enter Low Range..." class="form-control input-xs">
<input type="number" placeholder="Enter High Range..." class="form-control input-xs">
<button class="btn btn-primary" ng-click="assignWeights()">Select Model</button>
Controller model:
//set the initial root scope to empty object
$scope.root = {};
//define root weight
$scope.root.lowWeight = 0;
$scope.root.highWeight = 0;
I know I could just use ng-model="root.lowWeight" to set the value, but ng-model triggers on element input event.
How can I either:
a) Send the input values in via assignWeights(param1, param2)
b) Change ng-model to trigger input on button click (seems hacky, less preferred solution)
I also know I could use JS/jQuery to trigger the input event and block the input event, but that's a last ditch effort I will 99.9% not do.
Solution using seperate scope object: plunkr
Html:
Low: <input type="text" name="lowRange" ng-model="inputData.lowWeight">
High: <input type="text" name="highRange" ng-model="inputData.highWeight">
Js:
$scope.assignWeights = function() {
$scope.lowWeight = $scope.inputData.lowWeight;
$scope.highWeight = $scope.inputData.highWeight
}
In your assignWeights function, you could use a selector to retrieve the values of the inputs and then assign your scope variable values based on that. Just assign a name to each input.
E.g.
<input type="number" placeholder="Enter Low Range..." class="form-control input-xs" name="lowRange">
<input type="number" placeholder="Enter High Range..." class="form-control input-xs" name="highRange">
<button class="btn btn-primary" ng-click="assignWeights()">Select Model</button>
Controller:
$scope.assignWeights = function() {
$scope.root.lowWeight = document.querySelector('input[name="lowRange"]').value
$scope.root.highWeight = document.querySelect('input[name="highRange"]').value
}
Plunker: http://plnkr.co/edit/lm8GFA0CD0zWwgAMSLah?p=preview

AngularJs how to create a list of same services

I have a Service who can add by a user. It can be one or more.
I have a button to add a Service
<button type="button" class="btn btn-success" ng-click="addService()">
<span class=" glyphicon glyphicon-plus">
</span>Add Service
</button>
When i click Add Service angular should creare a new Service in a list of services.
I have two textareas for Informations of the Service.
<label for="usr">Name:</label>
<input type="text" class="form-control" id="name"></br>
<label for="usr">Service:</label>
<input type="text" class="form-control" id="service"></br>
When i click on the Add Service Button a knew Service Button should be generated with this textareas.
How can generate that and add the new Service to a list of services?
$scope.services = [];
$scope.addService = function() {
var newService = {
name : 'a name',
service : 'a service'
};
$scope.services.push(newService);
}
and the HTML
<div ng-repeat="service in services"><label for="usr">Name:</label>
<input type="text" class="form-control" value="{service.name}"></br>
<label for="usr">Service:</label>
<input type="text" class="form-control" value="{service.service}"></br></div>
You would use ng-model which will take care of 2 way binding fields to scope object
<label for="usr">Name:</label>
<input ng-model="newService.name"></br>
<label for="usr">Service:</label>
<input ng-model="newService.service"></br>
Then in controller
$scope.addService = function() {
// copy and push newService object to array
$scope.services.push(angular.copy($scope.newService));
// reset newService object to clear fields
$scope.newService = {};
}
If you use a form for this you can use angular validation and move the ng-click to ng-submit on the form. ng-submit won't trigger if validation fails

ng-model no longer updates after typing into text input

I am new to AngularJS and I am having a problem that I am having trouble solving, there was a similar question on stackoverflow but it didn't seem to help me out. I basically have a form that gets updated by ng-click, but once once I enter text into any of the text boxes, those text boxes no longer update.
This is my HTML
Edit Course:
<li ng-repeat="course in courses">
<p>
<a ng-click="Edit_Course(course.id)">{{course.course_name}}</a>
</p>
</li>
<div ng-show="showedit == 1">
<form novalidate ng-submit="edit_course()" class="simple-form">
<label for="form_course_name">Course</label>
<input type="text" id="form_course_name" ng-model="edit_course_name">
<label for="form_par">Par</label>
<input type="text" id="form_par" ng-model="edit_course_par">
<label for="form_course_location">Course Location</label>
<input type="text" id="form_course_location" ng-model="edit_course_location">
<input type="submit" id="submit" value="Edit Course" />
</form>
</div>
This is my function that is called when someone clicks on a link
$scope.Edit_Course = function (id) {
var course = {
'course_id' : id
};
$http({method: "POST", url: "http://www.dgcharts.com/editcourse", data: course})
.success(function(data, status, headers, config){
thecourse = data["course"];
$scope.edit_course_name = thecourse.course_name;
$scope.edit_course_par = thecourse.par;
$scope.edit_course_location = thecourse.course_location;
$scope.edit_course_id = thecourse.id;
$scope.showedit = 1;
})
}
your link requires a login.
if i have to guess about your problem, it may be related to angular scoping issue. try changing your ng-model binding to an object property instead. so in your html, instead of:
<input type="text" id="form_course_name" ng-model="edit_course_name">
do this
<input type="text" id="form_course_name" ng-model="course.edit_course_name">
and in your javascript, on the ajax callback, change it to:
$scope.course = {}; //only do this if $scope.course has not already been declared
$scope.course.edit_course_name = thecourse.course_name;
for more info on this issue, see: https://github.com/angular/angular.js/wiki/Understanding-Scopes

Categories