How do I get the changed element in a multiselect, using KendoUI? - javascript

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

Related

Call ViewBag in Jquery to get the value from controller

I am calling ViewBag.DeliveryDatebySupplier to update my textbox or just to alert. The value was always null. But when I debug and check the ViewBag in controller it has the date value.
Controller
if (ds.Tables[0].Rows.Count == 1)
{
string dt = ds.Tables[0].Rows[0]["DeliveryDt"].ToString();
DateTime myDate = Convert.ToDateTime(dt);
dt = myDate.ToString("yyyy-MM-dd");
ViewBag.DeliveryDatebySupplier = dt.ToString();
//Session["NewDeliveryDate"] = dt.ToString();
}
Jquery
function getDeliveryDateBySupplier() {
var _storeID = $('#ddlStoreID :selected').val();
var _SupplierID = $('#ddlSupplier :selected').val();
var url = "#Url.Content("~/Home/DeliveryDatebySupplier")";
$.ajax({
data: {
StoreID: _storeID,
SupplierID: _SupplierID
},
type: 'POST',
cache: false,
dataType: 'json',
url: url,
success: function (result) {
var newDeliveryDate = '#ViewBag.DeliveryDatebySupplier';
alert(newDeliveryDate);
},
error: function (ex) {
alert("Error getDeliveryDateBySupplier()");
}
});
}
Assuming the action called DeliveryDatebySupplier in the HomeController is the method to set ViewBag.DeliveryDatebySupplier, then this will not work unfortunately.
The script will be generated when the full page was generated and at that time, the value would not have been set yet.
I would advise, rather than using the viewbag, return the value when DeliveryDatebySupplier is called in your script.
Controller will be something like this then
if (ds.Tables[0].Rows.Count == 1)
{
string dt = ds.Tables[0].Rows[0]["DeliveryDt"].ToString();
DateTime myDate = Convert.ToDateTime(dt);
dt = myDate.ToString("yyyy-MM-dd");
return new JsonResult
{
data = new
{
DeliveryDatebySupplier = dt.ToString()
}
};
}
and jquery would change to something like this
success: function (data) {
if (data) {
var newDeliveryDate = data.DeliveryDatebySupplier
alert(newDeliveryDate);
}
else {
//Error
}
},

How to Execute ajax call after the scroller reaches the bottom

I'm correcting working on lazy loading for 200 array of objects and APIs are provided to me to extract JSON from the server (by passing index, row count as parameter for the get AJAX and on response I get the data and the Boolean of whether there are more rows or not). But the problem is that initially I was able to get the data of 10 from the 200 but while I set the scroll function on the div it displays duplicate data which are already appended on the div. Stucked in this problem for a day.
Hope you guys shed some light on me.
var listgen = (function() {
var mc = {};
mc.startindex = 1;
mc.rowcount = 10;
mc.hasmorerows = false;
mc.entity = "requests"
//Declared variables:
mc.initComponent = function() {
var entity = "requests";
mc.callAjaxForList(mc.entity, mc.startindex, mc.rowcount);
$("#reqbody").on('scroll', function() {
if (mc.hasmorerows && ($(this)[0].scrollHeight <= $(this).scrollTop() + $(this).innerHeight())) {
console.log('reached')
mc.callAjaxForList(mc.entity, mc.startindex, mc.rowcount);
}
console.log("scroll");
})
}
mc.callAjaxForList = function(entity, startindex, rowcount) {
var options = {
"list_info": {
"row_count": rowcount,
"start_index": startindex
}
}
$("#reqbody").addClass("loading");
$.ajax({
url: "/data/" + entity,
data: {
"input_data": JSON.stringify(options)
},
contentType: "application/json; charset=utf8",
type: "GET",
success: function(json) {
mc.hasmorerows = json.list_info.has_more_rows
mc.onDataLoading(json);
},
});
}
mc.onDataLoading = function(json) {
//this is where i append the data from the json
mc.startindex += mc.rowcount
}
return mc;
})()
listgen.initComponent();
Scroll is a very high-frequent event, so I think that you have several ajax calls with same data before actually your onDataLoading called, and range incremented. So I whould add mutex.
// ...
mc.loaging = false; // mutex
$("#reqbody").on('scroll', function(){
if(mc.hasmorerows && ($(this)[0].scrollHeight<=$(this).scrollTop()+$(this).innerHeight())){
console.log('reached')
if (!mc.loading) // add check here
mc.callAjaxForList(mc.entity,mc.startindex,mc.rowcount);
}
console.log("scroll");
})
}
mc.callAjaxForList= function(entity,startindex,rowcount){
// ...
mc.loading = true;
$.ajax({
// ...
success:function(json){
mc.hasmorerows=json.list_info.has_more_rows
mc.onDataLoading(json) ;
mc.loading = false;
},
error: ()=> mc.loading = false
});
}
So our mc.loading will tell us if ajax already completed (do not forget to reset it's value on ajax error)

Kendo jQuery Spreadsheet Date Values on Save

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.

How to get data with $.ajax() jquery and display to the HTML webpage

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);
}
});
}

If an ID is in the list already, don't allow to add product

I'm making a simple shopping cart type thing in javascript and basically I only want one of each item to be allowed to be added. I have the following code, my plan was to split out the myIDs and then loop through to see if that number already existed but it falls over on the split and i'm not sure if that's the best way of doing it really.
Heres what I have, any help will really be appreciated. Thanks
var myIDs;
jQuery(".selectItem").click(function () {
if (myIDs) {
var split = myIDs.split(",");
alert(split[0]);
}
addToCart(jQuery(this).data('id'));
});
function addToCart(id) {
jQuery.ajax({
type: "GET",
url: "feeds/prodxml.aspx?id=" + id,
dataType: "xml",
success: function (xml) {
jQuery(xml).find('Product').each(function () {
var sTitle = jQuery(this).find('Name').text();
var sPublisher = jQuery(this).find('Description').text();
jQuery("<li></li>").html(sTitle + ", " + sPublisher).appendTo("#addedItem ul");
jQuery('.hide-on-click').remove();
addItem(id);
});
},
error: function () {
alert("An error occurred while processing XML file.");
}
});
}
function addItem(itemID) {
if (!myIDs) {
myIDs = itemID;
} else {
myIDs = myIDs + "," + itemID;
}
alert(myIDs);
}
You could make myIDs an array instead of a string.
var myIDs = [];
Then you can modify the check to be
jQuery(".selectItem").click(function () {
if(jQuery.inArray(jQuery(this).data('id'), myIDs){
var split = myIDs.split(",");
alert(split[0]);
}
addToCart(jQuery(this).data('id'));
});
function addItem(itemID) {
myIds.push(itemID);
}
jQuery's inArray function can do this for you.
See: Jquery, checking if a value exists in array or not

Categories