I have an input on a webpage with a value like this 1,7,1,4,22,58,58,1,1,4,7
<input type="text" name="hello" id="thankyouforhelping" value="" aria-invalid="false">
I tried numerous ways to remove the duplicate from it but none of the ways work.
I tried: jQuery function to get all unique elements from an array? and jQuery function to get all unique elements from an array?
I get the value like this:
/* Grabbing up to date value to remove duplicates */
$upToDateValue = $('.wdrow-'+$projectrow+' .tasks-created input').val();
The value will always be numbers that are comma seperated but how can I remove all the duplicated numbers. And if you are willing how could I also sort it from low to high?
So that the end result would be 1,4,7,22,58
/* Removing duplicates */
$newValue = ???;
PS: I see a lot of answers on previously asked questions are javascript but I have my code in jQuery and I am struggling a lot with adapting those answers to my jQuery code. So I am sorry that this question is so closely related to others already available. Questions like this: Get all unique values in a JavaScript array (remove duplicates)
I have no clue how to adapt the accepted answer to my code.
Thanks everyone for helping!
##Heretic_Monkey helped me out a lot and this is the result:
$upToDateValue = $('.wdrow-'+$projectrow+' .tasks-created input').val();
/* Removing duplicates */
var values = $upToDateValue.split(','); values = [...new Set(values)]; values.sort(); $newValue = values.join(',');
/* Setting new value to input */
$('.wdrow-'+$projectrow+' .tasks-created input').val($newValue);
Combining answers from How to convert a comma separated string to an array?, Easy way to turn JavaScript array into comma-separated list?, and Get all unique values in a JavaScript array (remove duplicates), this is one way of performing the task:
// Get the value
var $upToDateValue = $('.wdrow-'+$projectrow+' .tasks-created input').val();
// Split into an array
var values = $upToDateValue.split(',');
// Remove the duplicates and make a new array
values = [...new Set(values)];
// Sort the new array
values.sort();
// Create a new comma-delimited string from the array
var $newValue = values.join(',');
// Set the new value to input
$('.wdrow-'+$projectrow+' .tasks-created input').val($newValue);
References for code used:
split
Set
... aka "spread syntax"
sort
join
I updated the code, you can copy the function and paste in your code.
then call it in your code using $newValue = unique(values)
Try this code:
function unique (value) {
const valueList = value.split(",")
const unique = valueList.filter((item, index, valueList) => {
return index === valueList.indexOf(item);
});
const sorted = unique.sort(function(a, b) { return a - b; });
return sorted.join(',')
}
/* you can use it this way */
const value = "1,7,1,4,22,58,58,1,1,4,7"
$newValue = unique(value)
/* printing */
console.log($newValue)
Related
I have an array in javascript. I've been trying to search the index but it is very frustrating. There is an object inside an array, and inside the object have an array as a value.
This is what the source code looks like:
rows = [{"id":"id0","cell":["array1","array2"]},{"id":"id1","cell":["array3","array4"]}];
I've tried this:
var v = {cell:["array1","array2"]};
rows.indexOf(v)
And also have a radio button:
<input type="radio" name='array' value="array1, array2">
jQuery here:
var i = $("input:checked").val().split(',');
rows.indexOf(i)
which has an index result of -1
Try this. It's a functional approach that loops through each index in rows, and returns true if there's a match.
var rows = [{"id":"id0","cell":["array1","array2"]},{"id":"id1","cell":["array3","array4"]}];
var index = rows.findIndex(function(i) {
return JSON.stringify(i.cell) == JSON.stringify(["array1","array2"])
});
console.log(index);
The output should return 0. The reason we need to convert both objects into JSON.strings is because of how javascripts handles the equality of two objects. You can read more about it here.
So, I have this function that, after an update, deletes elements from a table. The function, lets call it foo(), takes in one parameter.
foo(obj);
This object obj, has a subfield within called messages of type Array. So, it would appear something like this:
obj.messages = [...];
Additionally, inside of obj.messages, each element contains an object that has another subfield called id. So, this looks something like:
obj.messages = [{to:"You",from:"Me",id:"QWERTY12345.v1"}, ...];
Now, in addition to the parameter, I have a live table that is also being referenced by the function foo. It uses a dataTable element that I called oTable. I then grab the rows of oTable and copy them into an Array called theCurrentTable.
var theCurrentTable = oTable.$('tr').slice(0);
Now, where it gets tricky, is when I look into the Array theCurrentTable, I returned values appear like this.
theCurrentTable = ["tr#messagesTable-item-QWERTY12345_v1", ...];
The loop below shows how I tried to show the problem. While it works (seemingly), the function itself can have over 1000 messages, and this is an extremely costly function. All it is doing is checking to see if the current displayed table has the elements given in the parameter, and if not a particular element, delete it. How can I better write this function?
var theCurrentTable = oTable.$('tr').slice(0);
var theReceivedMessages = obj.messages.slice(0);
for(var idx = 0; idx < theCurrentTable.length; idx++){ // through display
var displayID = theCurrentTable[idx].id.replace('messagesTable-item-','').replace('_','.');
var deletionPending = true;
for(var x = 0; x < theReceivedMessages.length; x++){
var messageID = theReceivedMessages[x].id;
if(diplayID == messageID){
console.log(displayID+' is safe...');
deletionPending = false;
}
}
if(deletionPending){
oTable.fnDeleteRow(idx);
}
}
I think I understand your problem. Your <tr> elements have an id that should match an item id within your messages.
First you should extract the message id values you need from the obj parameter
var ids = obj.messages.map(function (m) { return '#messagesTable-item-' + m.id; });
This will give you all the rows ids you need to keep and then join the array together to use jQuery to select the rows you don't want and remove them.
$('tr').not(ids.join(',')).remove();
Note: The Array.prototype.map() function is only supported from IE9 so you may need to use jQuery.map().
You could create a Set of the message ID values you have, so you can later detect if a given ID is in this Set in constant time.
Here is how that would look:
var theCurrentTable = oTable.$('tr').slice(0);
var theReceivedMessages = obj.messages.slice(0);
// Pre-processing: create a set of message id values:
var ids = new Set(theReceivedMessages.map( msg => msg.id ));
theCurrentTable.forEach(function (row, idx) { // through display
var displayID = row.id.replace('messagesTable-item-','').replace('_','.');
// Now you can skip the inner loop and just test whether the Set has the ID:
if(!ids.has(displayId)) {
oTable.fnDeleteRow(idx);
}
});
So now the time complexity is not any more O(n.m) -- where n is number of messages, and m the number of table rows -- but O(n+m), which for large values of n and m can make quite a difference.
Notes:
If theCurrentTable is not a true Array, then you might need to use a for loop like you did, or else use Array.from(theCurrentTable, function ...)
Secondly, the implementation of oTable.fnDeleteRow might be that you need to delete the last rows first, so that idx still points to the original row number. In that case you should reverse the loop, starting from the end.
I'm using Kendo multi select as follow but i can't get selected values
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData= [];
var items = multiselect.value();
for (var itm in items)
{
selectedData.push(itm);
}
but array selectedData return indices of items in multiselect not values .
You can also assign the array, returned from the value() method, directly to the variable, e.g.:
var ms = $("#multiselect").kendoMultiSelect({
value: ["1", "2"]
}).data('kendoMultiSelect');
var selectedItems = ms.value();
console.log(selectedItems); // ["1", "2"]
Use this other one returns indices.
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData= [];
var items = multiselect.value();
for (var i=0;i<items.length;i++)
{
selectedData.push(items[i]);
}
Your original code doesn't look wrong. Are you sure you are getting only indices? Perhaps you should post your MultiSelect code as well. I found this question because I had the same problem and used the other answers for reference, but I found them overcomplicated. So let me answer in another complicated way :)
Here's what I've got. I know it's more code than you need, but I think it's important to see the full picture here. First let me set this up. There's a problem with the Kendo().MultiSelect.Name("SomeName") property if you are using it more than once. "Name" sets not only the html name, but the id as well, and you never want two ids with the same identifier. So in my code, I am appending a unique Id to my MultiSelect.Name property to ensure a unique id. I am putting the MultiSelect in each row of a table of people. I am showing this to make sure you are using the DataValueField property so you are able to get the selected values (not the text you see in the ui). If you are just showing a list of text values with no id behind them, perhaps that is why you are getting the wrong data?
#foreach (var cm in Model.CaseMembers)
{
<tr>
<td>
#(Html.Kendo().MultiSelect()
.Name("IsDelegateFor" + cm.CaseMemberId)
.Placeholder("is a delegate for..")
.DataTextField("FullName")
.DataValueField("CaseMemberId")
.BindTo(Model.Attorneys)
)
</td>
</tr>
}
then, later on, in my jQuery where I attempt to extract out the DataValueField (CaseMemberId), which is the array of selected values of the MultiSelect...
var sRows = [];
$('#cmGrid tr').each(function () {
// 'this' is a tr
$tr = $(this);
// create an object that will hold my array of selected values (and other stuff)
var rec = {};
rec.IsADelegateFor = [];
// loop over all tds in current row
$('td', $tr).each(function (colIndex, col) {
if (colIndex === 3) {
// make sure our MultiSelect exists in this td
if ($(this).find("#IsDelegateFor" + rec.CaseMemberId).length) {
// it exists, so grab the array of selected ids and assign to our record array
rec.IsADelegateFor = $(this).find("#IsDelegateFor" + rec.CaseMemberId).data("kendoMultiSelect").value();
}
}
}
// add this tr to the collection
sRows.push(rec);
}
so this is all a super verbose way of saying that this single line, as the other people mentioned works perfectly to grab the ids. There is no need to iterate over the .value() array and push the contents to another array!
rec.IsADelegateFor = $(this).find("#IsDelegateFor" + rec.CaseMemberId).data("kendoMultiSelect").value();
So in your original code, there is no reason the following should not work,
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData = [];
selectedData = multiselect.value();
console.log(selectedData);
unless
you don't have your MultiSelect set up properly in C# with DataValueField
you have multiple MultiSelects on the page with the exact same id and it's reading from a different one than you think.
You don't even have value fields, just a list of text.
var selected = $("#multi").data("kendoMultiSelect").value();
The solution given by volvox works.
Below is jquery version,
var multiselect = $("#SelectRoles").data("kendoMultiSelect");
var selectedData= [];
var items = multiselect.value();
$.each(items ,function(i,v){
selectedData.push(v);
});
I have written a custom function which returns a simple array. (it is a simple dirty 3D lookup over multiple sheets). Here is the code if it helps:
function get3DCellValues(startSheet, endSheet, cell) {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sum = 0;
var cellValues = [];
for (var i = (startSheet); i < endSheet; i++ ) {
var sheet = sheets[i];
var val = sheet.getRange(cell).getValue();
cellValues.push(val);
}
//Logger.log(cellValues);
return cellValues;
}
The problem is that when I return cellValues, the values overflow down the column. But I want it to overflow rightward through the row instead. Is there a way to do so? Thank you.
Google's guide has this to say about custom functions returning values:
Every custom function must return a value to display, such that:
If a custom function returns a value, the value displays in the cell
the function was called from. If a custom function returns a
two-dimensional array of values, the values overflow into adjacent
cells as long as those cells are empty
But this doesn't seem to be helpful to me.
Each entry in the array represents one row.
e.g. [[1,2],[3,4]] would be two rows [1,2] and [3,4].
[1,2,3,4] is interpreted as [[1],[2],[3],[4]], so it's 4 rows with one value each.
If you want only one row you could write [[1,2,3,4]].
So you'd have to change your code like this
...
var cellValues = [[]];
...
cellValues[0].push(val);
SpiderPig's very clear answer helped me immensely.
If you always want to return just one row, then you can also write your code as
...
var cellValues = [];
...
cellValues.push(val);
...
return [cellValues];
This will return an array that contains your cellValues array as its first and only entry
I'm trying to write a order form that shows the value of the selected items automatically. The backend is already complete, and on the front end each field, all radio / checkbox, look like this:
<input type="radio" name="shirt-size" value="shirt_size_m[18]" />
'18' being the price, everything else being irrelevant to the front end price calculation. I cannot change the naming convention, so I need to get the value between the brackets on all the <input>s on the page (or below the parent ID), add them together (on update), and append the value to another ID. Jquery is already in use on the site if that makes thongs easier.
I just need to be pointed in the right direction as my JS experience is limited to examples and minor customizations :)
Try using a simple regular expression with Javascript's replace, to replace all non-numeric characters with the empty string:
var str = "shirt_size_m[18]";
var theNumber = parseInt(str.replace(/[^0-9]/g, ''));
alert(theNumber);
Demo: http://jsfiddle.net/XvTaY/1/
You could try something like this:
function calculate_sum(form_id) {
var $form = $(form_id);
var sum = 0;
$checkbox_and_radios = $form.find('input[type=checkbox], input[type=radio]').each(function(){
sum += parseInt($(this).val().match(/^[^\[]+\[(\d+)\]$/)[1]);
});
return sum;
}
$(function(){
$("#id_of_the_form").find('input[type=checkbox], input[type=radio]').change(function(){
var sum = calculate_sum("#form_id");
// I don't know the type of your element containing
// the sum, so I put multiple solutions here:
// some input element
$('#another_id').val(sum);
// or another element
$('#another_id').html(sum);
// I'm assuming you don't really mean append
// If you're sure you want to append: (but then the old value won't be deleted)
$('#another_id').append(sum);
});
});
u can use:
var v;
v = $('#input-identifier').val();
v = v.split("[");
v = v[1];
v = v.split("]");
v = v[0];
// now v has the number