How to load JSON response on each rows input fields - javascript

I am novice in Programming and searching answer for the below problem in this site over days but couldn’t figure anything yet.
Firstly, A input form will prompt to the user, then the user will define how many rows there will be.
Then in the HTML table, each rows has 3 input fields(ID, Name, Number).
When a user gives an ID, the name and number of that ID will be placed in the next input fields of that row. For better understanding I am attaching an img.
demo_img.png
studentInfo.php page, Ajax response will set here:
<form class="" action="" method="POST">
<?php
$count = $_REQUEST["countID"]; //<--get the number from the user
for($i=1; $i<=$count; $i++){
?>
<tr>
<td>
<input type="number" name="id[]" class="id">
</td>
<td>
<input type="text" name="fname[]" class="fname">
</td>
<td>
<input type="number" name="num[]" class="num">
</td>
</tr>
<?php
}
?>
</form>
The Ajax portion:
$(".id").change(function(){
var sid = $(this).val();
$.ajax({
method: "GET",
url: "getData.php",
data: {sid: sid},
dataType: "json",
success: function(data, textStatus, jqXHR){
if(data.length == 0){
alert("No data found");
} else {
// I am stuck here. If I console.log(data) the JSON format coming from getData.php is showing like this: {name: 'JACKS DONUTS', num: '185'}
}
},
error: function(jqXHR, textStatus, errorThrown) {
//Show the error msg
}
});
});
Now, How do I set the result to the input fields.
Any suggestion in my code will be greatly appreciated. Thanks in advance.

Your requirement can be achieve by post an array of IDs to an URL e.g. getData.php using ajax.
['1001', '1002', '1003']
Then the getData.php will return an array of student data with ID as key.
{
"1001": {
"name": "Student A",
"number": 20
},
"1002": {
"name": "Student B",
"number": 21
},
"1003": {
"name": "Student C",
"number": 23
}
}
Once you retrieved the student data, try to look for the student data by using the input ID as key, if the data exists, append the data to the form.
if (data[inputId]) {
const studentData = data[inputId];
/* following methods will find input with class name and set the input value with given value */
setValue('name', studentData.name);
setValue('number', studentData.number);
}
Following is the SAMPLE by post the IDs to an API placeholder URL and SIMULATE the return data:
/* bind click event to buttons */
$(document).ready(function() {
$("#add-row").click(addRow);
$("#get-data").click(getData);
});
/* add extra row for input ID */
function addRow() {
$rowHtml = `
<tr class="student-data">
<td><input type="text" class="id" name="id[]" /></td>
<td><input type="text" class="name" /></td>
<td><input type="text" class="number" /></td>
</tr>
`;
$("#form-table").append($rowHtml);
}
/* get data when user submit */
function getData() {
const fieldset = $('#fieldset')
const message = $('#message')
const inputs = $(`input[name="id[]"]`)
/* get multiple ids as array where which by the user */
const ids = inputs.toArray().map(function(input) {
return input.value
})
/* store ids in a data object */
const dataToSubmit = {
ids: ids
}
/* url to post to submit the data e.g. "getData.php" */
/* following is just a demo url */
const url = "https://jsonplaceholder.typicode.com/posts"
$.ajax({
method: "POST",
url: url,
data: dataToSubmit,
dataType: "json",
beforeSend: function() {
/* disable the form when submitting */
fieldset.prop("disabled", true);
message.html('Getting data...');
},
success: function(data, textStatus, jqXHR) {
/* your data should return an array of objects with the key is the id */
/* e.g. {1001: {name: "Student A", number: 20}, 1002: {name: "Student B", number: 21},…} */
/* THIS IS NOT PART OF THE CODE! this is just a simulation of fetching the data */
data = JSON.parse(`{"1001":{"name":"Student A","number":20},"1002":{"name":"Student B","number":21},"1003":{"name":"Student C","number":23}}`);
/* fill the student data once retrieved data */
fillStudentData(data);
},
complete: function() {
/* enable back the form after form was submitted */
fieldset.prop("disabled", false);
message.html('');
}
});
}
function fillStudentData(data) {
$('.student-data').each(function() {
/* get the id by find the input with "id" class */
const inputId = $(this).children().find(".id")[0].value;
/* get student data using id key */
const studentData = data[inputId];
/* set the name and number if there is data found */
if (studentData) {
/* this function will find the inputs in "student-data" class and filled the input with value */
const setValue = (className, value) => {
$(this).children().find("." + className)[0].value = value;
};
setValue('name', studentData.name);
setValue('number', studentData.number);
}
})
}
<form style="display: flex;">
<fieldset id="fieldset">
<table id="form-table" border="1" cellpadding="10">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Number</th>
</tr>
</thead>
<tbody>
<tr class="student-data">
<td><input type="text" class="id" name="id[]" /></td>
<td><input type="text" class="name" /></td>
<td><input type="text" class="number" /></td>
</tr>
</tbody>
</table>
<span>Sample ID: 1001, 1002, 1003</span>
<button type="button" id="add-row">Add Row</button>
<button type="button" id="get-data">Get Data</button>
<span id="message"></span>
</fieldset>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Related

How to fix "ReferenceError: index is not defined" problem

I try to connect my REST server with JavaScript app. Using ajax query I get proper JSON, but I cannot bind it to my HTML website. I use data-bind in HTML:
<tbody>
<tr >
<td> <input type="number" data-bind="value: index" name="index" readonly> </td>
<td> <input type="text" data-bind="value: name" name="name"required> </td>
<td> <input type="text" data-bind="value: surname" name="surname"required> </td>
<td> <input type="date" data-bind="value: birthdate" name="birthdate" min="1950-01-01" max="2050-01-01" required> </td>
<td><button type="button" >Edit</button></td>
</tr>
</tbody>
In .js file I have below code:
'use strict';
var URL = 'http://localhost:8000/'
$(document).ready(function(){
var StateViewModel = function () {
var self = this;
self.students = ko.observableArray();
$.ajax({
url: URL + 'students',
type: 'GET',
dataType: 'json',
accepts: {
contentType: 'application/json'
}
}).done(function(result) {
console.log(result)
ko.mapping.fromJS(result, self.students);
});
}
var model = new StateViewModel();
ko.applyBindings(model);
});
And I get "ReferenceError: index is not defined" error.
When I request my REST appI get below JSON:
[
{
"index": 127001,
"name": "John",
"surname": "Smith",
"birthdate": "1996-11-11"
},
{
"index": 127002,
"name": "Abcd",
"surname": "Xyz",
"birthdate": "1996-11-01"
}
]
And in ajax function .done result is:
0: Object { index: 127001, name: "John", surname: "Smith", … }
1: Object { index: 127002, name: "Abcd", surname: "Xyz", … }
What could be the reason of "ReferenceError: index is not defined" error?
Your JSON looks fine, and there's nothing wrong with using 3 arguments for your mapping.fromJS with an empty object as the "options" argument. My guess is that it's a context issue with which object your markup is attempting to bind to. If you're still at the root level view-model the binding will fail because "Index" doesn't exist at the root level. You need a foreach binding to nest into the "students" child object.
var URL = 'http://localhost:8000/';
var sampleData = [{
"index": 127001,
"name": "John",
"surname": "Smith",
"birthdate": "1996-11-11"
},
{
"index": 127002,
"name": "Abcd",
"surname": "Xyz",
"birthdate": "1996-11-01"
}
];
var StateViewModel = function() {
var self = this;
self.students = ko.observableArray();
setTimeout(function() {
//console.log(sampleData)
ko.mapping.fromJS(sampleData, {}, self.students);
}, 1000);
}
var model = new StateViewModel();
ko.applyBindings(model);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<table>
<tbody data-bind="foreach: students">
<tr>
<td> <input type="number" data-bind="value: index" name="index" readonly> </td>
<td> <input type="text" data-bind="value: name" name="name" required> </td>
<td> <input type="text" data-bind="value: surname" name="surname" required> </td>
<td> <input type="date" data-bind="value: birthdate" name="birthdate" min="1950-01-01" max="2050-01-01" required> </td>
<td><button type="button">Edit</button></td>
</tr>
</tbody>
</table>
Taken straight from the docs
The first time you fetch data you should do this
var viewModel = ko.mapping.fromJS(data);
Then every time data is received from the server after that
ko.mapping.fromJS(data, viewModel);
I also managed to solve my problem in this way:
'use strict';
var URL = 'http://localhost:8000/'
$(document).ready(function(){
console.log("Abc")
ko.applyBindings(new customerViewModel());
});
function customerViewModel() {
var self = this;
self.studentsList = ko.observableArray();
$.ajax({
type: 'GET',
url: URL + 'students',
contentType: "application/json",
dataType: "json",
success: function(data) {
console.log(data)
var observableData = ko.mapping.fromJS(data);
var array = observableData();
self.studentsList(array);
},
error:function(jq, st, error){
alert(error);
}
});
}
And using foreach
data-bind="foreach: studentsList"

Laravel 'Illegal string offset 'leave_form' issue with array

I have an edit page where I display the data from a leave application form. I get an error 'Illegal string offset 'leave_form' when I update my form. I am using Vue.js and PHP. I manage to get the other data saved, that is in the leaveData object. When I try to save in the dateFrom in array of objects. leaveData['leave_form'] then I get the error. I suspect the problem lies in my foreach statement under the controller.
My array (just an example that I copied and pasted from console so you can see the object keys and values):
leaveData = [
alternativeName: "testos",
applicantSignature:"1",
applicantSignedDate:"2017-12-12",
contactDetailDuringLeave:"999999",
created_at:"2017-12-12 08:05:44",
created_by:6,
id:21,
leave_form = [
conditionsOfPay:"test",
created_at:"2017-12-12 08:05:44",
dateFrom:"2017-12-12",
dateTo:"2017-12-15",
id:15,
leave_application_id:21,
name:"Vacation Leave",
numberOfDays:2,
]
]
Here is a part of my blade HTML(just the leave_form part):
<tbody>
<tr v-for="leave in leaveData.leave_form">
<th scope="row">#{{ leave.name }}</th>
<td><input v-pikaday="leave.dateFrom" class="form-control" v-model="leave.dateFrom" type="text"/></td>
<td><input v-pikaday="leave.dateTo" class="form-control" v-model="leave.dateTo" type="text"/></td>
<td><input class="form-control" type="text" name="numberOfDays" v-model="leave.numberOfDays"></td>
<td><input class="form-control" type="text" name="conditionsOfPay" v-model="leave.conditionsOfPay"></td>
</tr>
</tbody>
Here is my Vue.js:
var leaveApply = new Vue({
el: '#leaveCreate',
data: {
leaveData: <?php echo $leaveApplication ?>,
getUserData: <?php echo $users ?>,
},
methods: {
submitForm: function(){
var that = this;
var value = that.leaveData;
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $("#_token").attr("content")
}
});
$.ajax({
url: '/admin/internal/leave/update/' + value.id,
type: 'POST',
data: {
leaveData: that.leaveData,
personnelNumber: that.leaveData.personnelNumber,
user_id: that.leaveData.user_id,
alternativeName: that.leaveData.alternativeName,
contactDetailDuringLeave: that.leaveData.contactDetailDuringLeave,
applicantSignature: that.leaveData.applicantSignature,
applicantSignedDate: that.leaveData.applicantSignedDate,
managerApproval: that.leaveData.managerApproval,
managerSignedDate: that.leaveData.managerSignedDate,
},
success: function(response) {
toastr.success('Leave Application Updated');
},
error: function(error){
toastr.error('Something went wrong');
}
});
},
},
});
My Controller:
public function update (Request $request, $id){
$leaveApplication = LeaveApplication::with('user','leaveDept','leaveForm', 'leaveTask')->find($id);
$leaveApplication->personnelNumber = $request->input('personnelNumber');
$leaveApplication->alternativeName = $request->input('alternativeName');
$leaveApplication->contactDetailDuringLeave = $request->input('contactDetailDuringLeave');
$leaveApplication->managerApproval = filter_var($request->input('managerApproval'), FILTER_VALIDATE_BOOLEAN);
$leaveApplication->applicantSignature = filter_var($request->input('applicantSignature'), FILTER_VALIDATE_BOOLEAN);
$leaveApplication->applicantSignedDate = $request->input('applicantSignedDate');
$leaveApplication->managerSignedDate = $request->input('managerSignedDate');
foreach($request->input('leaveData') as $leaveData){
$leaveApplication->dateFrom = $leaveData['leave_form']['dateFrom'];
$leaveApplication->update();
}
$leaveApplication->update();
return response()->json($leaveApplication);
}
$leaveApplication = LeaveApplication::with('user','leaveDept','leaveForm', 'leaveTask')->find($id);
$leaveApplication->dateFrom = $leaveData['leave_form']['dateFrom'];
You have leave_form and LeaveForm. Maybe the problem is here. Also this code
foreach($request->input('leaveData') as $leaveData){
$leaveApplication->dateFrom = $leaveData['leave_form']['dateFrom'];
$leaveApplication->update();
}
repeats the process and saves the last foreach value into your record.
It also means that you are calling update 2 times.

Manipulating array data to actually save, write, and change the data content

I am new to AngularJS and so far I'm loving it but I am having a hard time manipulating my data with it. I have an array of data with the attributes name:'', description:'', type:'', ... etc ... and I have enough data but not enough yet for me to upload it onto a server. My problem is that I want to be able to change and update my data using a form or input.
Here is my scripts/admin.js where I implement function submitTheForm() that I call with the submit button.
angular.module('myApp')
//filter to get a specific $scope.campaigns using its id
.filter('getById', function() {
return function(input, id) {
var i=0, len=input.length;
// alert(input.length);
for (; i<len; i++) {
if (+input[i].id === +id) {
return input[i];
}
}
return input[0];
};
})
.controller('AdminCtrl', ['$scope', '$filter', function($scope, $filter) {
//<--ARRAY OF DATA with multiple attributes<--
$scope.campaigns = [
{ name:'', description'', etc... etc...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
];
$scope.selectCampaign = function(object) {
$scope.selectedCampaign = object;
};
$scope.submitTheForm = function(item, event) {
if (confirm("Are you sure you want to edit?") == true) {
alert("--> Submitting form");
var dataObject = {
name : $scope.selectedCampaign.name, description: $scope.selectedCampaign.description, type: $scope.selectedCampaign.type, imgSrc: $scope.selectedCampaign.imgSrc, brand: $scope.selectedCampaign.brand, region: $scope.selectedCampaign.region, location: $scope.selectedCampaign.location, contact: $scope.selectedCampaign.contact, url: $scope.selectedCampaign.url, id: $scope.selectedCampaign.id
};
console.log(dataObject);
var campaign = $scope.selectedCampaign;
var id = campaign.id;
var found = $filter('getById')($scope.campaigns, id);
// setTimeout(function(){ $scope.$apply($scope.selectedCampaign = dataObject); });
}
};
}]);
Here is my main.html where I have my input and submit button
<div class="row modalDetail">
<div class="col-xs-12 col-sm-6 col-md-6 detailLeft text-left">
<div class="middle-allign">
<h1 class="detailName">
<input type="text" ng-model="selectedCampaign.name" name="name">
</h1>
<div class="detailDescription">
<textarea rows="5" cols="71" name="description" ng-model="selectedCampaign.description"></textarea>
</div>
<table class="detailTable table">
<tbody>
<tr>
<td class="bolder">Brand</td>
<td>
<input type="text" ng-model="selectedCampaign.brand" name="brand" >
</td>
</tr>
<tr>
<td class="bolder">Campaign Type</td>
<td>
<input type="text" ng-model="selectedCampaign.type" name="type">
</td>
</tr><tr>
<td class="bolder">Region</td>
<td>
<input type="text" ng-model="selectedCampaign.region" name="region">
</td>
</tr>
<tr>
<td class="bolder">Contact</td>
<td>
<input type="text" ng-model="selectedCampaign.contact" name="contact">
</td>
</tr>
<tr>
<td class="bolder">Location</td>
<td>
<input type="text" ng-model="selectedCampaign.location" name="location">
</td>
</tr>
<tr>
<td class="bolder">URL</td>
<td>
<input type="text" ng-model="selectedCampaign.url" name="url">
</td>
</tr>
</tbody>
</table>
<div class="detailCta">
<button class="btn detailButton" ng-click="submitTheForm()">Submit Campaign</button>
</div>
</div>
</div>
I am trying to utilize 'ng-model' to bind the data and it all works fine but it does not actually change the array content within my main.html. When I refresh it all just goes back to how my array content is. This is because I haven't actually over-written my array content. How can I go about making a absolute change/over-write to the actual object within the array content?
I feel as though it is as simple as $scope.campaigns.push(campaign); except instead of 'push' it would be 'update' or 'over-write'
If you want to store the values in the server, you should see ngResource to create entry points to get and save (and delete) data. Alternatively, you can use the lower level service $http.
If you want to store the data in your current script (it will last until the page is refreshed in the browser - F5), you should do some changes:
.controller('AdminCtrl', ['$scope', '$filter', '$rootScope', function($scope, $filter, $rootScope) {
//<--ARRAY OF DATA with multiple attributes<--
if ($rootScope.campaigns === undefined) {
$rootScope.campaigns = [
{ name:'', description'', etc... etc...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
{...Lots of Data...},
];
}
$scope.campaigns = $rootScope.campaigns;
//don't even think this above line is needed, since $scope inherits from $rootScope, but I've put it for clarity.
$scope.selectCampaign = function(object) {
$scope.selectedCampaign = object;
};
$scope.submitTheForm = function(item, event) {
if (confirm("Are you sure you want to edit?") == true) {
alert("--> Submitting form");
var dataObject = {
name : $scope.selectedCampaign.name, description: $scope.selectedCampaign.description, type: $scope.selectedCampaign.type, imgSrc: $scope.selectedCampaign.imgSrc, brand: $scope.selectedCampaign.brand, region: $scope.selectedCampaign.region, location: $scope.selectedCampaign.location, contact: $scope.selectedCampaign.contact, url: $scope.selectedCampaign.url, id: $scope.selectedCampaign.id
};
console.log(dataObject);
var campaign = $scope.selectedCampaign;
var id = campaign.id;
var found = $filter('getById')($scope.campaigns, id);
}
};
}]);
Notice how I bind it to $rootScope.campaigns - so if you navigate to another ng-view and then come back, the data is still here.
However, if you want your data survive the F5, you must either use the server side options I gave you. or use Local Storage.

Update UI after ajax response

I am new to knocokout.js so i have a table in which data is bind using ajax call.When user click on edit button row information is fill to a form which is on same page below the table.
after ajax call which update the data into database successfully , i am not able to show the changed value of particular object which is changed into table. If i refresh then its show new value .
Here is my html and js code .
<div id="body">
<h2>
Knockout CRUD Operations with ASP.Net Form App</h2>
<h3>
List of Products</h3>
<table id="products1">
<thead>
<tr>
<th>
ID
</th>
<th>
Name
</th>
<th>
Category
</th>
<th>
Price
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody data-bind="foreach: Products">
<tr>
<td data-bind="text: Id">
</td>
<td data-bind="text: Name">
</td>
<td data-bind="text: Category">
</td>
<td data-bind="text: formatCurrency(Price)">
</td>
<td>
<button data-bind="click: $root.edit">
Edit</button>
<button data-bind="click: $root.delete">
Delete</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
</td>
<td>
</td>
<td>
Total :
</td>
<td data-bind="text: formatCurrency($root.Total())">
</td>
<td>
</td>
</tr>
</tfoot>
</table>
<br />
<div style="border-top: solid 2px #282828; width: 430px; height: 10px">
</div>
<div data-bind="if: Product">
<div>
<h2>
Update Product</h2>
</div>
<div>
<label for="productId" data-bind="visible: false">
ID</label>
<label data-bind="text: Product().Id, visible: false">
</label>
</div>
<div>
<label for="name">
Name</label>
<input data-bind="value: Product().Name" type="text" title="Name" />
</div>
<div>
<label for="category">
Category</label>
<input data-bind="value: Product().Category" type="text" title="Category" />
</div>
<div>
<label for="price">
Price</label>
<input data-bind="value: Product().Price" type="text" title="Price" />
</div>
<br />
<div>
<button data-bind="click: $root.update">
Update</button>
<button data-bind="click: $root.cancel">
Cancel</button>
</div>
</div>
</div>
Code
function formatCurrency(value) {
return "$" + parseFloat(value).toFixed(2);
}
function ProductViewModel() {
//Make the self as 'this' reference
var self = this;
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");
var Product = {
Id: self.Id,
Name: self.Name,
Price: self.Price,
Category: self.Category
};
self.Product = ko.observable();
self.Products = ko.observableArray(); // Contains the list of products
// Initialize the view-model
$.ajax({
url: 'SProduct.aspx/GetAllProducts',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
// debugger;
$.each(data.d, function (index, prd) {
self.Products.push(prd);
})
//Put the response in ObservableArray
}
});
// Calculate Total of Price After Initialization
self.Total = ko.computed(function () {
var sum = 0;
var arr = self.Products();
for (var i = 0; i < arr.length; i++) {
sum += arr[i].Price;
}
return sum;
});
// Edit product details
self.edit = function (Product) {
self.Product(Product);
}
// Update product details
self.update = function () {
var Product = self.Product();
$.ajax({
url: 'SProduct.aspx/Update',
cache: false,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: "{Product:" + ko.toJSON(Product) + "}",
success: function (data) {
console.log(data.d);
self.Product(null);
alert("Record Updated Successfully");
},
error: function (data) {
console.log(data);
}
})
}
// Cancel product details
self.cancel = function () {
self.Product(null);
}
}
$(document).ready(function () {
var viewModel = new ProductViewModel();
ko.applyBindings(viewModel);
});
and my webmethod which called by ajax request is as follow :
// to update product
[WebMethod]
public static testModel.Product Update(testModel.Product Product)
{
testEntities db = new testEntities();
var obj = db.Products.First(o => o.Id == Product.Id);
obj.Name = Product.Name;
obj.Price = Product.Price;
obj.Category = Product.Category;
db.SaveChanges();
return obj;
}
and JSON response of ajax call as follow
{"d":{"__type":"testModel.Product","Id":31,"Name":"12","Category":"12","Price":1350,"EntityState":2,"EntityKey":
{"EntitySetName":"Products","EntityContainerName":"testEntities","EntityKeyValues":
[{"Key":"Id","Value":31}],"IsTemporary":false}}}
Here's what's happening. Here: self.Products.push(prd) prd is just a plain javascript object with plain property values, nothing is observable. You're pushing the raw object onto the Products observableArray, which updates the DOM because Products was changed and KO is watching it. When you click 'edit', you set self.Product to that plain object and the KO updates the DOM with this object and its values because Product was changed and KO is watching it. So now your Product form below displays, you see the information, and it looks like you can edit the properties but KO won't update those property changes because KO isn't watching them. They're not observable. Change:
$.each(data.d, function (index, prd) {
//self.Products.push(prd);
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
});
General helpful tips
<div data-bind="if: Product">
This only evaluates once when you bind the viewModel to the DOM with ko.applyBindings. Since self.Product has an initial value of null KO removes this altogether.*Note: I was thinking of #if for some reason.
This works like the visible binding except when the value is false, the element and its children are removed from the DOM. So there is more DOM manipulation going on than necessary. You probably just want to hide this <div>
I would recommend changing this to:
<div data-bind="visible: Product">
Instead of this:
<input type="text" data-bind="text: Product().Name" />
<input type="text" data-bind="text: Product().Category" />
<input type="text" data-bind="text: Product().Price" />
Try this instead:
<div data-bind="with: Product">
<input type="text" data-bind="text: Name" />
<input type="text" data-bind="text: Category" />
<input type="text" data-bind="text: Price" />
</div>
Consider renaming self.Product to self.SelectedProduct to make it more clear what it is for.
I'm not sure what this is doing in the ViewModel:
//Declare observable which will be bind with UI
self.Id = ko.observable("");
self.Name = ko.observable("");
self.Price = ko.observable("");
self.Category = ko.observable("");
var Product = {
Id: self.Id,
Name: self.Name,
Price: self.Price,
Category: self.Category
};
You don't use them in the DOM. You were kind of on the right path with this though. Instead, before the ProductViewModel, create this:
function ProductModel(data) {
var self = this;
data = data || {};
self.Id = ko.observable(data.Id);
self.Name = ko.observable(data.Name);
self.Price = ko.observable(data.Price);
self.Category = ko.observable(data.Category);
}
Now instead of:
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
});
We can just do this:
$.each(data.d, function (index, prd) {
self.Products.push(new ProductModel(prd));
});
Hopefully that will get you headed in the right direction.
There is something to change:
Replace
$.each(data.d, function (index, prd) {
self.Products.push(prd);
})
With:
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.observable(prd.Id),
Name: ko.observable(prd.Name),
Price: ko.observable(prd.Price),
Category: ko.observable(prd.Category)
});
})
Use ko.observable to make your properties notify the view of its changes so that the view can update accordingly. This should work but not perfect because this is 2 way binding, so whenever you update the values in your div, the view model object is updated immediately and even if your ajax fails to update the data in backend, making the data out of synch between client side and server side.
For better solution. You need to have a look at protectedObservable
$.each(data.d, function (index, prd) {
self.Products.push({
Id: ko.protectedObservable(prd.Id),
Name: ko.protectedObservable(prd.Name),
Price: ko.protectedObservable(prd.Price),
Category: ko.protectedObservable(prd.Category)
});
})
Inside your self.update ajax success function, trigger a change:
success: function (data) {
var product =self.Product();
product.Id.commit();
product.Name.commit();
product.Price.commit();
product.Category.commit();
self.Product(null);
alert("Record Updated Successfully");
}
And revert if there is error:
error: function (data) {
product.Id.reset();
product.Name.reset();
product.Price.reset();
product.Category.reset();
}
Update:
Remember to change all the places with Product.Property to Product.Property() to get its property value . For example: arr[i].Price should be changed to arr[i].Price()
Add self.Products.push(data.d); to the update() functions success handler.
success: function (data) {
console.log(data.d);
self.Product(null);
self.Products.push(data.d);
alert("Record Updated Successfully");
},
You need to update the array so that it reflects in bound html.

Putting dynamic sets of fields in form into JSON with JavaScript

I have a form that has a dynamic number of rows. Each row has 3 fields, a hidden id, code, and exchange.
<form id="form_in_question">
<table>
<tr>
<td>0</td>
<td>
<input type="hidden" id="id[]" value="123" />
<input type="input" id="code[]" value="abc" />
</td>
<td>
<select id="exchange[]">
<!-- Options... -->
<select>
<td>
<tr>
<!-- unlimited rows... -->
</table>
</form>
I am trying to get an object that looks like:
data: {
"0": {
id: "123",
code: "abc",
exchange: "2"
},
"1": {
id: "124",
code: "bcd",
exchange: "4"
}
}
So I can pass it a JSON object via AJAX like:
$("#dialogEditor").dialog('option', 'buttons', {'Save' : function() {
/* Define variables */
var data = $("#form_in_question").serializeArray();
$.ajax({
url: 'ajax.codes.php',
dataType: 'json',
data: {
action: "update_codes",
entryId: entry,
data: data
},
type: 'POST',
success: function() {
ui.showMsg("Codes Updated");
}
});
This is what the JSON looks like that I am actually passing:
data[0][name] id[]
data[0][value]
data[1][name] code[]
data[1][value] zxc
data[2][name] exchange[]
data[2][value] 15
data[3][name] id[]
data[3][value]
data[4][name] code[]
data[4][value] BVA
data[5][name] exchange[]
data[5][value] 5
or the raw data:
action=update_codes&ResortId=12&data%5B0%5D%5Bname%5D=id%5B%5D&data%5B0%5D%5Bvalue%5D=&data%5B1%5D%5Bname%5D=code%5B%5D&data%5B1%5D%5Bvalue%5D=zxc&data%5B2%5D%5Bname%5D=exchange%5B%5D&data%5B2%5D%5Bvalue%5D=15&data%5B3%5D%5Bname%5D=id%5B%5D&data%5B3%5D%5Bvalue%5D=&data%5B4%5D%5Bname%5D=code%5B%5D&data%5B4%5D%5Bvalue%5D=BVA&data%5B5%5D%5Bname%5D=exchange%5B%5D&data%5B5%5D%5Bvalue%5D=5
I tried a method I found on SO but it didn't group the 3 fields together.
The following code should work:
var data = [];
var table = $("table").get()[0];
for (var i=0; i<table.rows.length; i++) {
var tableRow = table.rows[i];
var rowData = {};
var inputData = {};
inputData["id"] = $("input[id^='id']", $(tableRow.cells[1])).val();
inputData["code"] = $("input[id^='code']", $(tableRow.cells[1])).val();
inputData["exchange"] = $("select[id^='exchange']",$(tableRow.cells[2])).val();
rowData[$(tableRow.cells[0]).text()] = inputData;
data.push(rowData);
}
console.log(JSON.stringify(data));

Categories

Resources