ng-model not bindings - javascript

I get jsondata from controller and use ng-repeat to fill table
<tr ng-repeat="customer in customerlist">
<td>{{customer.fistname}}</td>
<td>{{customer.lastame}}</td>
<td id="emailid" >{{customer.email}}</td>
<td><a href="#" class="customeropt" id="customeropt" ng-click="editCustomer(customer.email)" >Edit</a></td>
</tr>
After I get data from the table and I want to set data to input for editing
I get data by using editCustomer(customer.email)
$scope.editCustomer = function(email){
var edit = this;
$scope.emailid = email;
console.log(email);
return email;
}
How set data to an input field or another html tag.
When I use ng-model and ng-change for any HTML tag it's not update when I click on "Edit"
<h2 ng-model="changedData" ng-change="changeData()">Email: {{changedData}}</h2>
<input ng-model="changedData" ng-change="changeData()">
The ng-change function:
$scope.changeData = function(){
$scope.changedData;
console.log($scope.changedData);
}
And sorry for my English is not my native.

Try this:
html:
<tr data-ng-repeat="customer in customerlist">
<td>{{customer.fistname}}</td>
<td>{{customer.lastame}}</td>
<td id="emailid" >{{customer.email}}</td>
<td>
<a href="#" class="customeropt" id="customeropt"
data-ng-click="editCustomer(customer)" >Edit</a>
</td>
</tr>
<h2>Email: {{ customer.email }}</h2>
<input data-ng-model="customer.email">
js:
$scope.customer =
{
firstname: "",
lastname: "",
email: ""
}
$scope.editCustomer = function(customer){
$scope.customer.firstname = customer.firstname;
$scope.customer.lastname = customer.lastname;
$scope.customer.email = customer.email;
}
Let me know how it goes.
Edit
Here's why it works: The ng-repeat directive on creates a customer object for each row . The ng-click event on passes the customer object for that row . Inside the event handler, editCustomer, a scope variable name $scope.customer is assigned the properties of the customer. The has a two-way binding with $scope.customer using the ng-model directive so that the scope variable is changed whenever the value changes.

Related

ng-model not binding to input data within ng-repeat

Using AngularJs 1.6.7, I have created a table which pulls project details from a database and displays these details within a table. Each row has a modify/update button using ng-show/hide. When modify is clicked, the div changes to editable input fields, when update is clicked, the new input data will be update in the database.
I am trying to access input items within an ng-repeat and using ng-model to bind the input to update projects in a database using Flask.
The problem is that when I access the data in AJS once update is clicked, no data has binded to the new input values.
My HTML looks like this.
<tr data-ng-repeat="(key, value) in projects" >
<td>
<div data-ng-hide="edditable_project[value.project_name]">{[value.project_name]}
</div>
<div data-ng-show="edditable_project[value.project_name]">
<input class="form-control" data-mg-model="updatedProjectName" value="{[value.project_name]}">
</div>
</td>
<td>
<button class="btn btn-danger add-on pull-right btn-sm" data-ng-click="removeProject(value)">Delete</button>
<button class="btn btn-primary add-on btn-sm pull-right" data-ng-hide="edditable_project[value.project_name]" data-ng-click="modify(value.project_name)">Modify</button>
<button type="submit" class="btn btn-success pull-right btn-sm " data-ng-show="edditable_project[value.project_name]" data-ng-click="update(value)">Update</button>
</td>
</tr>
And my controller looks like this:
app.controller('projectSettingsController', ['$scope', '$http', function($scope, $http) {
$scope.modify = function(project) {
$scope.edditable_project[project] = true;
};
$scope.update = function(project) {
data = {
project_name: $scope.updatedProjectName,
}
console.log($scope.updatedProjectName);
// Update project.
$http.post('/api/project/update-project', data).then(function(response) {
toastr.success(response.data);
});
$http.get('/api/project/get-all-project-details').then(function (response) {
$scope.projects = response.data;
});
$scope.edditable_project[project] = false;
};
}]);
The current output for ng-model="updatedProjectName" is undefined.
Am I doing something wrong within the scope?
well you should define your binding vairable in the scope of your controller like
$scope.updatedProjectName =""; by default it`s null as you have described, but for all your inputs you will have one data binding, i think you should have some
$scope.data={};
tr data-ng-repeat="(key, value) in projects" >
<input data-ng-model="data[key]">
</tr>
and you don`t need to set value in your input, ng-model will make it for you
You are trying to access a variable which is defined inside of ng-repeat's scope. What you would want to do in this case is pass value and work on the project variable inside the update function.
Change your mark up to data-mg-model="value.project_name". Now the ng-model binds to same. When the update completes set the latest data(if needed) as properties on project. It will reflect in the view because of 2 way data binding
Inside update you should do as follows
$scope.update = function(project) {
// Update project.
$http.post('/api/project/update-project', project).then(function(response) {
toastr.success(response.data);
// If needed set new properties on the project variable
// based on the response
});
}
You seem to have a typo:
<input class="form-control" data-mg-model="updatedProjectName" value="{[value.project_name]}">
Use ng-model instead of mg-model.

ng model not working

I am trying to set the value using ng-model (passing values via function).
My codes look like
Input tag:
<input name="comments" ng-model="comments" class="form-control" type="text">
Grid Table :
<tr ng-repeat="value in values">
<td><input type="radio" ng-click="callvalues(value.CUSTID);"></td>
Angularjs code:
$scope.callvalues = function($scope,custID){
alert("custID");
};
I am getting custID is not defined. I try to hardcore values
$scope.callvalues = function($scope,custID){
$scope.comments = "122";
};
NO error in console but it's also not working.
remove $scope parameter from your function
from
$scope.callvalues = function($scope,custID){
to
$scope.callvalues = function(custID){
If what you mean is click in radio button and alert value you can try this code
$scope.callvalues = function(custID){
alert(custID);
$scope.comments = custID;
};
plnkr
https://plnkr.co/edit/CYi3e2D0xLkWksr9p4y8?p=preview
Grid Table
<tr ng-repeat="value in values">
<td><input type="radio" ng-model="selectedRadio" ng-value="value.CUSTID" ng-click="callvalues(selectedRadio);"></td>
Controller
$scope.callvalues = function(custID){
//console.log($scope.selectedRadio);
alert(custID);
};
You don't need to pass $scope as method argument. You can read it's values in any method inide of Controller.
$scope.callvalues = function(custID){
alert("custID");
$scope.comments = custID;
};

KnockoutJS - Print iteration index as input name

I am trying to create my first KnockoutJS form view in combination with Spring MVC's #ModelAttribute binding.
Data is loaded over Ajax and populated with KnockoutJS
Data is added over KnockoutJS
Data is removed over Ajax and KnockoutJS
Data will be saved with an normal POST submit to Spring MVC controller.
To bind the form inputs to a Spring MVC controller, I need the iteration index from KnockoutJS. So I tried following:
But the values from my database are never bound like they are when I am bind them with data-bind='value: key'. Can you help me, finding the mistake?
JSP:
<form:form modelAttribute="configurationHelper" action="/saveConfigurationList.htm" method="POST" id="configuration-form" class="form-inline">
<tbody data-bind="foreach: configurations">
<tr>
<td>
// this is working
<input data-bind='value: key' class="form-control input-sm" type="text"/>
// this is not working
<input data-bind='attr:{value: key, name:configurationHelper.configurations[$index].key' class="form-control input-sm" type="text"/>
</td>
<td>
<a href='#' data-bind='click: $root.removeConfiguration' class="ordinary-tooltip" title='<spring:message code="general.delete"/>'>
<i class="fa fa-lg fa-trash-o "></i>
</a>
</td>
</tr>
</tbody>
</form:form>
ModelView:
function ConfigurationViewModel() {
var self = this;
self.configurations = ko.observableArray([]);
self.loadConfigurations = function() {
$.ajax({
type : "POST",
url : "/loadConfigurationList.htm",
success : function(response) {
var responseArray = JSON.parse(response);
var mappedConfigurations = $.map(responseArray.configurations, function(configuration) {
return new Configuration(configuration);
});
self.configurations(mappedConfigurations);
},
error : function(e) {
alert('Error: ' + e.status);
}
});
}
self.saveConfigurationList = function() {
$("#configuration-form").submit();
}
self.addConfiguration = function() {
self.configurations.push({
id: 0,
key: "",
value: "",
});
};
self.removeConfiguration = function(configuration) {
if(confirm(springMessageGeneralDeleteReally)){
$.ajax({
type : "POST",
url : "/deleteConfiguration.htm",
data: {"configurationId": configuration.id},
success : function(response) {
self.configurations.remove(configuration);
},
error : function(e) {
alert('Error: ' + e.status);
}
});
}
};
}
function Configuration(data) {
this.id = ko.observable(data.id);
this.key = ko.observable(data.key);
this.value = ko.observable(data.value);
}
Summary:
Knockout should only take care of binding the values (loaded with AJAX) to the inputs and display the correct input-name. (to bind the input-value back to the Spring MVC controller)
configurationHelper is a request parameter and should not bother Knockout. It is only available to bind the list of configurationHelper.configurations to Spring MVC.
Following form is properly bound to Spring MVC controller:
<form:form modelAttribute="configurationHelper" action="/leina16/configuration/saveConfigurationList.htm" method="POST" id="configuration-form" class="form-inline">
<form:input path="configurations[0].key" class="form-control input-sm"/>
</form:form>
Now I want to extend inputs with Knockout JS so I need at least the data-bind attribute as well as the foreach: $index from Knockout:
<tbody data-bind="foreach: configurations">
<input data-bind='attr:{value: key, name:"configurations[$index].key}' class="form-control input-sm" type="text"/>
</tbody>
But the snipped above is neither bound to Spring MVC controller method nor the values are populated.
You have a missing } and are probably getting an error about Knockout being unable to parse bindings.
Change:
'attr:{value: key, name:configurationHelper.configurations[$index].key'
To:
'attr:{value: key, name:configurationHelper.configurations[$index].key}'
As configurationHelper is defined outside of your foreach loop, you'll need to reference this using $parent or $root:
'attr:{value: key, name:$parent.configurationHelper.configurations[$index].key}'
Solution:
Add quotes to "non-Knockout" elements and use $index() function.
<tbody data-bind="foreach: configurations">
<tr>
<td>
<input data-bind='attr:{value: key, name:"configurations["+$index()+"].key"}' class="form-control input-sm" type="text"/>
</td>
</tr>
</tbody>

knockout observable array update not updating the UI

When I update an observable element of Knockout the UI is not getting update
HTML
<tbody data-bind="foreach: students, visible: !students().isDeleted">
<tr>
<td data-bind="text: RollNo"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Phone"></td>
<td data-bind="text: Email"></td>
<td>
Edit
Delete
</td>
</tr>
</tbody>
Javascript
function StudentModel(student){
this.RollNo = ko.observable(student.RollNo);
this.Name = ko.observable(student.Name);
this.Phone = ko.observable(student.Phone);
this.Email = ko.observable(student.Email);
this.isDeleted = ko.observable(student.isDeleted);
this.isEdited = ko.observable(student.isEdited);
}
function StudentViewModel() {
//Array of students
this.students = ko.observableArray();
//Data retrived from the server
var listStudent= JSON.parse(#Html.Raw(ViewBag.StudentsList));;
var mappedStudents = $.map(listStudent, function(student) { return new StudentModel(student) });
//Map it to show the data
this.students(mappedStudents);
//Delete student
this.deleteStudent= function(student){
var stu = this.students()[this.students.indexOf(student)];
stu.isDeleted(true);
}.bind(this);
When I click on Delete the UI is not updated... When I try stu.isDeleted=true; still it does not works... Any help would be appreciated...
Fiddle
The problem is in the databinding.
visible: !students().isDeleted
This looks up the isDeleted property in the observable array. Which doesn't exist, so it is false and will always show all the elements.
If you want to hide the students the visible binding should be on the <tr>.
If you want to remove the student from the observable array you can just remove it.
http://jsfiddle.net/8fALs/2/

AngularJS: How to make local variables work which are not part of ng-repeat

I have an application where I am receiving a list of person objects in persons and iterating over to build a table dynamically.
The code looks like this:
<table>
<tr ng-repeat = "personInfo in persons">
<td>{{personInfo.name}}</td>
<td>{{personInfo.gender}}</td>
<td>
<select ng-model="selected_address" ng-options="address.placename for address in personInfo.address"></select>
<span ng-show="make_address_editable==false;">{{selected_address.address}}</span>
<input type="text" style="width: 22em;" ng-show="make_address_editable" ng-model="selected_address.address" />
<input style="margin-left: 2em;" type="button" value="{{btnValue}}" ng-show="selected_address" ng-click="make_address_editable=!make_address_editable; changeBtnValue($index)"/>
</td>
</tr>
</table>
The part where I am stuck is how to change the value of input[type="button"] or {{btnValue}} individually for each person which edits/saves a person's address. I don't want to assign it as a property on the personInfo object as I would not need it later. In my controller I initialize the value of make_address_editable and btValue but I'm only able to control the behavior of make_address_editable on ng-click for each person. If I call a function on ng-click which changes btnValue depending on what the user clicked it changes the btnValue for each row/person.
Controller code:
$scope.make_address_editable = false;
$scope.btnValue = 'Edit';
$scope.changeBtnValue = function(index){
if ($scope.btnValue === 'Edit'){
$scope.btnValue = 'Save';
}
else{
$scope.btnValue = 'Edit';
}
}
I don't know how to use index in the method to change btnValue for each person in the table.
Any help would be much appreciated.
Thanks!
There should be no problem including a btnValue within the personInfo object as this is a ViewModel and you are really driving the view (value of button) based on what is in that model. You may not be using it later in terms of using that value when persisting the person to a datastore, but your view is definitely using it constantly as it is keeping the two-way binding in sync.
You should really be putting make_address_editable inside your personInfo model as well since I don't think you want to have a "global" flag for each individual person. Having make_address_editable directly on $scope will prevent you from tracking it on a person by person basis.
If you really must make a local variable, you can try this. See jsfiddle I made starting with your example:
angular.module('coolApp', [])
.controller('PersonCtrl', function ($scope) {
$scope.persons = [{'name': 'Alex', 'gender': 'Male', 'address': [{'placename': 'Home', 'address': '1234 Dr'},{'placename': 'Office', 'address': '12345 Dr'}]}, {'name': 'Alexis', 'gender': 'Female', 'address': [{'placename': 'Home', 'address': '12345 Dr'},{'placename': 'Office', 'address': '123456 Dr'}]}];
//$scope.make_address_editable = false;
//$scope.btnValue = 'Edit';
$scope.changeBtnValue = function (viewModel) {
if (viewModel.editable === true) {
viewModel.btnValue = 'Save';
} else {
viewModel.btnValue = 'Edit';
}
};
});
Then use ng-init within your repeater to make a viewModel object that is local to the repeater scope. This will keep your persons from changing:
<div ng-app="coolApp">
<div ng-controller="PersonCtrl">
<table>
<tr ng-repeat="personInfo in persons" ng-init="viewModel={btnValue: 'Edit', editable: false}">
<td>{{personInfo.name}}</td>
<td>{{personInfo.gender}}</td>
<td>
<select ng-model="selected_address" ng-options="address.placename for address in personInfo.address"></select> <span ng-show="viewModel.editable===false;">{{selected_address.address}}</span>
<input type="text" style="width: 22em;" ng-show="viewModel.editable" ng-model="selected_address.address" />
<input style="margin-left: 2em;" type="button" value="{{viewModel.btnValue}}" ng-show="selected_address" ng-click="viewModel.editable=!viewModel.editable; changeBtnValue(viewModel);" />
</td>
</tr>
</table>
<br><br>
{{persons}}
</div>
</div>
btnValue is supposed to change for all "persons". But I think you'd want it to change for specific "person" objects only.
There is an ugly way to do this. Pass the event to the function.
ng-click="make_address_editable=!make_address_editable; changeBtnValue($event)"
Inside the changeBtnValue function, change the "value" attribute of the corresponding input tag.
$scope.changeBtnValue = function(event){
var inputTag = event.target;
}
"inputTag" variable will hold HTML Element object representing the corresponding input tag. Change the "value" attribute of the tag to "save"/"edit" or anything else.
THis method is ugly because you manipulate the View from within the JS code. People usually try to avoid this.

Categories

Resources