So I have a Kendo jQuery spreadsheet that is bound to a remote datasource. The fields in the spreadsheet are also data-driven, so I have a process in place that will loop over all of the columns and apply a validation to the column based on the type of data. When I apply the validation to date values it seems like all the values are converted into JavaScript Date objects.
This causes me two problems. 1. When I go to save the data it sends the date object to the server, not a string of the mm/dd/yyyy. 2. It treats blank values as 12/30/1899.
Here is a portion of the code that I use:
var record_id = 1;
var columnData = {
field_name1: {"title":"FIELD1", "type":"string", "width":50, "order":0},
field_name2: {"title":"FIELD2", "type":"date", "width":50, "order":1}
};
var columnMap = ['field_name1', 'field_name2'];
// The following code executes in the event that is triggered when the data is successfully read.
function readSource(e) {
$.ajax({
url: './spreadsheet.php',
data: { id: record_id, action: 'list' },
dataType: 'json',
method: 'POST',
success: function(result) {
e.success(result);
$.each(columnData, function(field, data) {
var range = toColumnName(columnMap.indexOf(field) + 1) + '2:' + toColumnName(columnMap.indexOf(field) + 1) + (result.count + 1);
var validator = false;
var format = '';
switch (data.type) {
case 'date': {
validator = {
dataType: 'date',
comparerType: 'between',
from: 'DATEVALUE("1/1/2000")',
to: 'DATEVALUE("1/1/2100")',
allowNulls: true,
showButton: true,
type: 'reject',
titleTemplate: 'Date Error',
messageTemplate: 'Enter a valid date between 1/1/2000 and 1/1/2100.'
};
format = 'mm/dd/yyyy';
break;
}
}
if (validator !== false) {
sheet.range(range).validation(validator);
}
if (format === '') {
sheet.range(range).format(format);
}
});
}
});
}
// On save
function submitSource(e) {
$.ajax({
url: './spreadsheet.php',
data: { action: 'update', id: record_id, records: e.data },
method: 'POST',
dataType: 'json',
success: function (result) {
e.success(result.Updated, 'update');
e.success(result.Created, 'create');
e.success(result.Destroyed, 'destroy');
}
}
// Convert index to column letter (1 => 'A', 27=>'AA')
function toColumnName(num) {
for (var ret = '', a = 1, b = 26; (num -= a) >= 0; a = b, b *= 26) {
ret = String.fromCharCode(parseInt((num % b) / a) + 65) + ret;
}
return ret;
}
I will include a link to a screenshot that shows what happens to cells that should be blank when I click the save button. The first row in the image had dates that were populated. The rows below that were blank.
What needs to change to allow the appropriate date values to be sent back to the server and how can I avoid the trouble with the blanks?
The spreadsheet.php code probably doesn't properly format the date.
December 30, 1899 is the epoch date for Microsoft Excel and others:
https://en.wikipedia.org/wiki/Epoch_(reference_date)#Notable_epoch_dates_in_computing
So you are probably feeding the value "1" instead of null.
Related
I need help in retrieving data from https://jsonplaceholder.typicode.com/. Here is my AJAX call:
$.ajax({
url: root + '/posts/',
data: { userId: 1 },
type: "GET",
dataType: "json",
success: function(data) {
$("#posts").html("<p><h3>" + data[0].title + "</h3></p>");
console.log(data);
$("#posts").append("<p>" + data[0].body + "</p>");
console.log(data);
}
});
How can I set the data: userId to not only 1 but a range of values like 1 to 5 or 1 to 10? And how do I append all of them by displaying in my html file?
Simple click way
HTML:
<div data-action="getUsers" data-users="1,2,3,4,5">Get Users</div>
JS:
$(function(){
$("[data-action=getUsers]").on("click", function(){
// get userId someway
var $this = $(this);
var data = $this.data();
var users_string = data.users;
var userIds_str_array = users_string.spilt(","); // this will turn a string into an array of strings split by given char
var userIds_int_array = [];
var length = (userIds_str_array.length - 1);
// convert to ints, might be overkill, strings might be fine, this is your call
for(let i = length; i--;){ // short hand for-loop, use if order doesnt matter
let value = userIds_str_array[i];
let test_val = parseInt(value);
// short hand if
// return true to skip iteration
isNaN(test_val) === false ? userIds_int_array.push(value) : return true;
}
// make sure you are not wasting your time.
if(userIds_int_array.length > 1){
return GetUserFromPosts(user, function(responce){
if(responce.users){
if(responce.users.length > 0){
// func call
return doSomethingWithUsers(responce.users);
}else{
return false; // no users in array
}
}else{
return false; // there was probably a 500 error
}
});
}
else
{
return false // no users in array
}
})
})
function GetUserFromPosts(userId_arr, callback){
var data = {userId: userId_arr}; // I assume your api can accept an array, if not, you have to do seperate calls for each one.
$.ajax({
url: root + '/posts/',
data: data,
success: function(data) {
console.log(data);
return callback(data);
}
});
}
I am working in ASP.NET MVC 5.
I am trying to deserialize dates coming from the server in JSON format. The JSON arrives and when I try to deserialize the dates the debugger just stops and don't show any errors other the in the console, which I can't understand.
This is my code so far:
$(document).ready(function () {
$.ajax({
type: 'GET',
url: '/Home/GetDates',
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (dates) {
var date = dates[0];
var desDate = $.parseJSON(date, true);
console.log(desDate);
}
});
});
Here are some pics on the errormessage and that a have data coming in.
Here is a link to the docs I have been looking at. Docs
The data returned from the ajax call is already parsed, so dates is an array containing strings, and dates[0] is the string/Date(14984....)/ etc.
To parse the string, remove everything but the numbers, and use that timestamp to create a Date object.
$(document).ready(function () {
$.ajax({
type : 'GET',
url : '/Home/GetDates',
dataType : "json",
contentType : "application/json; charset=utf-8",
success: function (dates) {
var d = dates[0];
var unix = +d.replace(/\D/g, '');
var date = new Date(unix);
var desDate = date.getFullYear() + '/' +
(date.getMonth()+1) + '/' +
date.getDate();
console.log(desDate);
}
});
});
You need to execute the JavaScript inside your string variable as
var dateVar = eval(dates[0]);
This will give you the date but not in a proper format which you want. For the proper format user either moment.js or simply create your own lines of code like
var finalDate = new Date(dateVar).toISOString().split('T')[0];
console.log(finalDate);
The new Date() is again needed here so that we can make use of toISOString() and get the proper date format.
Because you are referring to this jQuery parseJSON automatic date conversion for Asp.net and ISO date strings you need to include the jQuery extension defined there.
Indeed, in jQuery parseJSON(jsonString) accepts only one argument while you are using an extension.
Moreover, your dates variable is an array of string, and not a json string.
//
// Look at the end....
//
/*
* jQuery.parseJSON() extension (supports ISO & Asp.net date conversion)
*
* Version 1.0 (13 Jan 2011)
*
* Copyright (c) 2011 Robert Koritnik
* Licensed under the terms of the MIT license
* http://www.opensource.org/licenses/mit-license.php
*/
(function ($) {
// JSON RegExp
var rvalidchars = /^[\],:{}\s]*$/;
var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
var dateISO = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.,]\d+)?Z/i;
var dateNet = /\/Date\((\d+)(?:-\d+)?\)\//i;
// replacer RegExp
var replaceISO = /"(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:[.,](\d+))?Z"/i;
var replaceNet = /"\\\/Date\((\d+)(?:-\d+)?\)\\\/"/i;
// determine JSON native support
var nativeJSON = (window.JSON && window.JSON.parse) ? true : false;
var extendedJSON = nativeJSON && window.JSON.parse('{"x":9}', function (k, v) {
return "Y";
}) === "Y";
var jsonDateConverter = function (key, value) {
if (typeof(value) === "string") {
if (dateISO.test(value)) {
return new Date(value);
}
if (dateNet.test(value)) {
return new Date(parseInt(dateNet.exec(value)[1], 10));
}
}
return value;
};
$.extend({
parseJSON: function (data, convertDates) {
/// <summary>Takes a well-formed JSON string and returns the resulting JavaScript object.</summary>
/// <param name="data" type="String">The JSON string to parse.</param>
/// <param name="convertDates" optional="true" type="Boolean">Set to true when you want ISO/Asp.net dates to be auto-converted to dates.</param>
if (typeof data !== "string" || !data) {
return null;
}
// Make sure leading/trailing whitespace is removed (IE can't handle it)
data = $.trim(data);
// Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
if (rvalidchars.test(data
.replace(rvalidescape, "#")
.replace(rvalidtokens, "]")
.replace(rvalidbraces, ""))) {
// Try to use the native JSON parser
if (extendedJSON || (nativeJSON && convertDates !== true)) {
return window.JSON.parse(data, convertDates === true ? jsonDateConverter : undefined);
}
else {
data = convertDates === true ?
data.replace(replaceISO, "new Date(parseInt('$1',10),parseInt('$2',10)-1,parseInt('$3',10),parseInt('$4',10),parseInt('$5',10),parseInt('$6',10),(function(s){return parseInt(s,10)||0;})('$7'))")
.replace(replaceNet, "new Date($1)") :
data;
return (new Function("return " + data))();
}
} else {
$.error("Invalid JSON: " + data);
}
}
});
})(jQuery);
var date = '{"date": "\\/Date(1498435200000)\\/"}';
var desDate = $.parseJSON(date, true);
console.log(desDate);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Javascript with AJAX inside another function
http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/dynamic-update/
From this example, instead of placing the first 19 points with random values, I want to pass a value from my server through AJAX.
And I am talking about the code here.
series: [{
name: 'Random data',
data: (function () {
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
}]
And since the key of series is also data I have no idea how I am gonna get data from AJAX GET call.
The AJAX call that I want to use is:
$.ajax({
type: "GET",
url: "/getData",
success: function(data) {
var y1 = data.count;
series.addPoint([x, y1], true, true);
}
});
But I tried to use this but it does not seem to work, like the following:
series: [{
name: 'Random data',
data: (function () {
var data1 = [],
time = (new Date()).getTime(),
i;
$.ajax({
type: "GET",
url: "/getData",
success: function(data) {
var y1 = data.count;
for (i = -19; i <= 0; i += 1) {
data1.push({
x: time + i * 1000,
y: data.count
});
}
}
});
return data1;
}())
}]
Please let me know how to GET for the Highchart data
First off see this reference for why you can't return data from your outer function like you're trying to:
How do I return the response from an asynchronous call?
Then, understanding that you will have to use the data from the success handler, that means that you will have to move the ajax call outside of the data declaration and do it afterwards, but you will have to recognize that the data will NOT be available until sometime later when the ajax call finishes. You cannot use it immediately. If you need to know when the data is available, then put the data into the data structure and call some other function from the success handler.
Like they said the AJAX call is async = not blocking, it means that the browser is making the ajax call in your function and instantly goes on at the next line, in your case return data1 but the data1 var is not updated since the ajax call is still being executed.
Documentation:http://api.jquery.com/deferred.done/
There are also some things I don't understand in your code, did you try to lint hit with JSHint or JSLint?, here is my version with some corrections:
// define var outside of function so they are not scoped
var time = (new Date()).getTime(),
data1,series;
$.ajax({
type: "GET",
url: "/getData",
success: function(data) {
// since you are using i only here just define it in the cycle
for (var i = -19; i <= 0; i += 1) {
data1.push({
x: time + i * 1000,
y: data.count
});
}
}
}).done(function() {
series = {
name: 'Random data',
data: data1
};
});
I have a multiselect-list that acts as holder for a list of tags. I can't seem to figure out how to properly get the value of the item being changed and passed along with the changed-event. Here's my Kendo multiselect:
#(Html.Kendo().MultiSelect()
.Name("tags")
.Placeholder("No tags selected for this unit")
.BindTo(new SelectList(Model.TagsAvailable))
.Events(e => e
.Select("select")
.Change("change"))
.Value(Model.TagsSelected.ToArray())
)
And here are my js-methods:
function select(e) {
var dataItem = this.dataSource.view()[e.item.index()];
var param = dataItem.Text;
var url = '/UnitDetails/TagUnit/#Model.UnitId';
$.ajax({
url: url,
data: { selectedItem: param },
type: 'GET',
dataType: 'json',
success: function (data) {
// ...
},
error: function () {
// ...
}
});
};
function change(e) {
var dataItem = this;
var param = dataItem.element.context.innerText;
var url = '/UnitDetails/UnTagUnit/#Model.UnitId';
$.ajax({
url: url,
data: { selectedItem: param },
type: 'GET',
dataType: 'json',
success: function (data) {
// ...
},
error: function () {
// ...
}
});
};
My problem beeing that I feel the assignment of param is just quick and dirty. Surely, there must be some other, more correct way of going about this?
There is no easy way (afaik) for knowing the changes. So, let do it by ourselves.
First, I'm going to save the old value using the following function.
function saveCurrent(multi) {
multi._savedOld = multi.value().slice(0);
}
Where multi is the multi-select that we pass to the function as argument (so you can use the function for multiple multiselects).
Then, you need to implement change as follow:
change : function (e) {
// Retrieve previous value of `multiselect` saved using previous function
var previous = this._savedOld;
// These are current values.
var current = this.value();
// Let's save it for the next time
saveCurrent(this);
// The difference between previous and current are removed elements
var diff = $(previous).not(current).get();
console.log("removed", diff);
// The difference between current and previous, are added elements
diff = $(current).not(previous).get();
console.log("added", diff);
}
Running example here http://jsfiddle.net/OnaBai/MapVN/
Nice answer OnaBai! very useful and helpful.
I had the same Nickla's problem.
But, I needed to "save current values" at dataBound event. And it works (logging the changed values).
If you start deleting an item, it fails because the function recognizes the "change" as an "item add".
This is what I did
function dataBound(ev) {
saveCurrent(this);
}
function saveCurrent(multi) {
multi._savedOld = multi.value().slice(0);
}
function change(ev) {
var previous = this._savedOld;
var current = this.value();
saveCurrent(this);
var diff = $(previous).not(current).get();
console.log("removed", diff);
var removedSkill = diff;
console.log("removedSkills", removedSkill);
diff = $(current).not(previous).get();
var addedSkill = diff;
console.log("added", diff);
console.log("addedSkills", addedSkill);
if (addedSkill.length > 1 || removedSkill.length > 1) {
if (addedSkill.length > 1) {
addedSkill = addedSkill[addedSkill.length - 1];
alert("Added skill code: " + addedSkill.toString());
}
if (removedSkill.length > 1) {
removedSkill = removedSkill[removedSkill.length - 1];
alert("Removed skill code: " + removedSkill.toString());
}
}
else {
if (addedSkill.length > 0) {
alert("Added skill code: " + addedSkill.toString());
}
if (removedSkill.length > 0) {
alert("Removed skill code: " + removedSkill.toString());
}
}
$.ajax({
url: "SomeUrl",
type: "POST",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({ removedSkill: removedSkill, addedSkill: addedSkill })
});
}
Thanks again!
Iván
I'm using jquery and jquery ui 1.8.7. I'm creating an inline datepicker when the page loads, then in my ajax success function, I'm calling $('#mydiv').datepicker('refresh'); (I'll post code below).
If the data has been returned from ajax (eg. on the refresh), beforeShowDay calls the highlightDays() function. I know that I'm hitting highlightDays with the correct data twice before everything crashes to a halt and I get an error "TypeError: Cannot read property 0 of undefined".
It seems like the events array is being destroyed after a certain amount of time, but I don't know enough about ajax to really say what's happening. Can anyone point me in the right direction to fix this?
function highlightDays(date) {
var day = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
console.log(typeof(events)); // This will return as an object twice before throwing an the above mentioned error
if($.inArray(day, events) !== -1) {
return new Array(true, '');
} else {
return new Array(false, '');
}
}
function getEventData() {
return $.ajax({
url: Drupal.settings.basePath + 'correct_path',
data: search+'&path='+window.location.pathname,
dataType: 'json',
type: 'POST',
success: function(data, textStatus, jqXHR) {
// save our returned data
events = new Object();
events = data;
$('#mydiv').datepicker("refresh");
}
});
}
function createDatepicker() {
// Attach datepicker to the parent div so it returns as
// inline.
$('#mydiv').datepicker({
dateFormat: 'yy-mm-dd',
speed: 'immediate',
altField: '#edit-date-filter-value-datepicker-popup-1',
beforeShowDay: function(date) {
if(typeof (_event_days) === 'undefined') {
return new Array(true, '');
} else {
highlightDays(date);
}
},
});
$('#myinput').hide();
}
getEventData();
createDatepicker();
The following code is what ended up working for me. Two big differences. Reworking the highlightDays function and adding all data returned from the ajax call to a global events array, to be used later in highlightDays.
var events = [];
function highlightDays(date) {
var dayClass = [true, ''];
var date = $.datepicker.formatDate('yy-mm-dd', new Date(date));
$.each(events, function(key, value) {
if (date === value[0]) {
dayClass = [true, "ui-state-highlight"];
return dayClass;
} else {
return dayClass;
}
});
return dayClass;
}
function getEventData() {
return $.ajax({
url: 'myurl',
data: search+'&path='+window.location.pathname,
dataType: 'json',
type: 'POST',
success: function(data, textStatus, jqXHR) {
$.each(data, function (index, value) {
events.push([value]);
});
// popup is the date input field
// attaching datepicker to the parent div makes
// it an inline picker
popup.parent().datepicker('refresh');
}
});
}
function createDatepicker() {
popup.parent().datepicker({
dateFormat: 'yy-mm-dd',
beforeShowDay: highlightDays
});
popup.hide();
}
function getSearchString() {
// Return a search string to pass to the ajax call
var search = window.location.search;
if(search !== '') {
while(search.charAt(0) === '?') {
// remove the leading question mark in the search string
search = search.substr(1);
}
}
return search;
}
// If our popup selector exists, create the datepicker and get event data
if (popup.length) {
var search = getSearchString();
getEventData();
createDatepicker();
}