Putting dynamic sets of fields in form into JSON with JavaScript - 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));

Related

How to load JSON response on each rows input fields

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>

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.

Add item to array Angular

I have a table with these fields: product, lot, input1, input2. You can clone a line, and you can add a new line.
What I want to do is that for each row you can add a new Lot created by a "number" and by "id" that user write in the input field under the Select lot. And I wanted that the script add the new Lot in the json data and the lot 's option list.
This is the function for add that I tried to do:
$scope.addLot = function() {
var inWhichProduct = row.selectedProduct;
var newArray = {
"number": row.newLot.value,
"id": row.newLot.id
};
for (var i = 0; i < $scope.items.length; i++) {
if ($scope.items[i].selectedProduct === inWhichProduct) {
$scope.items[i].selectedLot.push(newArray);
}
}
};
-->> THIS <<-- is the full code.
Can you help me?
I think your question is a little too broad to answer on Stack Overflow, but here's an attempt:
<div ng-app="myApp" ng-controller="myCtrl">
<table>
<tr ng-repeat="lot in lots">
<td>{{ lot.id }}</td>
<td>{{ lot.name }}</td>
</tr>
</table>
<p>name:</p> <input type="text" ng-model="inputName">
<p>id:</p> <input type="text" ng-model="inputId">
<button ng-click="addLotButton(inputId, inputName)">Add</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.2/angular.min.js"></script>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.lots = [{
name: "test",
id: 1
},
{
name: "test2",
id: 2
}
];
$scope.addLot = function(lotId, lotName) {
var newLotObject = {
name: lotName,
id: lotId
};
$scope.lots.push(newLotObject);
};
$scope.addLotButton = function(id, name) {
$scope.addLot(id, name);
};
$scope.addLot(3, "Another test");
});
</script>
Basically this code just takes some input and adds an object to the scope for that input. The table is created using an ng-repeat of this data. It's not great code at all but it's just a quick example.
The push method adds newArray to selectedLot array. It's not working on the JSON data but on arrays. If you want to have the JSON, you can give a try to :
var myJsonString = JSON.stringify(yourArray);
It will create a JSON string based on the parameter
Maybe you should try to structure your data to make lots as properties of products.
{
products: [
{id: 1, lots: [{id:1}, {id:2}]},
{id: 2, lots: [{id:1}, {id:2}]}
]
}
To add a lot to a product :
product = products[0];
product.lots.push(newArray);
Change the fallowing:
html:
<button ng-click="addLot(row.selectedProduct.id,row.newLot.value,row.newLot.id)">Add</button>
js:
$scope.addLot = function(id,val,lotId) {
// console.log(id);
var inWhichProduct = id;
var newArray = { "value": val, "id": lotId };
//console.log($scope.items)
angular.forEach($scope.items,function(v,i){
if($scope.items[i].id == id )
{
$scope.items[i].lots.push(newArray);
console.log($scope.items[i].lots);
}
});
};
http://plnkr.co/edit/W8eche8eIEUuDBsRpLse?p=preview

How to update the edited item of knockout js observablearray in UI part?

How to update the knockout js observablearray in UI part..Initially Im editing a item and in update function i'm trying to update a particular item so im sending the current item object to service and getting the updated vales as response. Inside the response I need to update the observablearray as well the UI too.. I have tried some thing like this and its not working for me... please check in http://jsfiddle.net/up8rB/20/
<div data-bind="ifnot: Role()">
<label for="description">Description</label>
<input type="text" data-bind="value: Description" class="form-control" placeholder="Enter the description..." />
<button data-bind="click: $root.create"> Create</button>
</div>
<div data-bind="if: Role">
<label for="description">Description</label>
<input type="text" data-bind="value: Role().Description" class="form-control" placeholder="Enter the description..." />
<button data-bind="click: $root.update"> Save</button>
</div>
<table id="example1" class="table table-bordered table-striped" data-bind="visible: Roles().length > 0">
<thead>
<tr>
<th>RoleID</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody data-bind="foreach: Roles">
<tr>
<td data-bind="text: $data.RoleID"></td>
<td data-bind="text: $data.Description"></td>
<td>
<button data-bind="click: $root.edit" >Edit</button>
<button data-bind="click: $root.delete" >Delete</button>
</td>
</tr>
</tbody>
</table>
function RoleViewModel() {
var self = this;
self.RoleID = ko.observable("0");
self.Description = ko.observable().extend({
required: { message: 'Please supply description ..' }
});
var Role = {
RoleID: self.RoleID,
Description: self.Description
};
self.Role = ko.observable();
self.Roles = ko.observableArray();
$.ajax({
url: 'Service.svc/RoleCollection',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (data) {
self.Roles(data); //Put the response in ObservableArray
}
});
self.edit = function (Role) {
self.Role(Role);
}
self.update = function () {
var Role = self.Role();
$.ajax({
url: '..service.svc/UpdateRole',
cache: false,
type: 'PUT',
contentType: 'application/json; charset=utf-8',
data: ko.toJSON(Role),
success: function (data) {
for (var i = 0; i < self.Roles().length; i++) {
alert(self.Roles()[i].RoleID());
if (self.Roles()[i].RoleID() === data.RoleID) {
self.Role(self.Roles()[i]);
break;
}
}
}
})
}
var viewModel = new RoleViewModel();
ko.applyBindings(viewModel);
Your issue is that your are assigning items to your observable array that aren't themselves observable, so your UI is not updating when they change.
I did some renaming, as I found it confusing with so many things named 'Role', but the first change was your array setup:
var roles = [{
RoleID: ko.observable(1),
Description: ko.observable('First item')
}, {
RoleID: ko.observable(2),
Description: ko.observable('Second item')
}];
I also modified the update function:
self.update = function () {
var _Role = self.Role();
for (var i = 0; i < self.Roles().length; i++) {
if (self.Roles()[i].RoleID === _Role.RoleID) {
self.Roles()[i] = _Role();
break;
}
}
}
See the Updated Fiddle
Update:
Your json response should populate the observableArray correclty, but you may have an issue when setting it back after the update, try setting the properties rather than overwriting the element:
self.update = function () {
var _Role = self.Role();
for (var i = 0; i < self.Roles().length; i++) {
if (self.Roles()[i].RoleID === _Role.RoleID) {
self.Roles()[i].RoleID = _Role().RoleID;
self.Roles()[i].Description = _Role().Description;
break;
}
}
}
See the Updated Fiddle

Categories

Resources