How to remove duplicate values from dynamic select in Javascript? - javascript

trying to figure this out with no such luck. Basically we populating a select with values from the service that it's being retrieved from. But there are duplicates in the select. Here's the code that's doing it. I'd like to remove the duplicates from what's getting returned that are in the "theProduct.name". I know this question has been asked before but I can't figure this out. The image attached is the select where it's happening. Thanks
function populateSearchProducts(data) {
var theData = data.data.results;
$field.empty().append('<option value=""> </option>');
for (var p in theData) {
var theProduct = theData[p];
$field.append('<option value="'+theProduct.id+'">'+theProduct.name+'</option>');
}
}

Try a filter to remove duplicates from the input data:
function populateSearchProducts(data) {
var theData = data.data.results.filter(function(item, pos, self) {
return self.indexOf(item) == pos;
});
$field.empty().append('<option value=""> </option>');
for (var p in theData) {
var theProduct = theData[p];
$field.append('<option value="'+theProduct.id+'">'+theProduct.name+'</option>');
}
}

function populateSearchProducts(data) {
data = data.data.results;
const dupes = new Set();
for(const {name, id} of Object.values(data)){
if(dupes.has(name)) continue;
$field.append(`<option value='${id}' > ${name} </option>`);
dupes.add(name);
}
}

You can keep track of the items already added to the DOM and then use a filter before adding new elements.
In the code below, the filter is looking at the id of each element to filter them out. If you want, you could use name (or any other attribute) to detect the duplicates and filter them out.
Something along the lines of:
var dataArray = [
{id: 1, name: 'one'},
{id: 2, name: 'two'},
{id: 3, name: 'three'},
{id: 4, name: 'four'},
{id: 2, name: 'two'}, // dupe
{id: 5, name: 'five'},
{id: 3, name: 'three'} // dupe
]
function populateSearchProducts(data, $field) {
//var theData = data.data.results;
var theData = data;
$field.empty().append('<option value=""> </option>');
// to keep track of the ones already in the drop-down
var alreadyAdded = [];
for (let p of theData) {
if(alreadyAdded.filter( item => item.id === p.id ).length <= 0 ){
$field.append('<option value="'+p.id+'">'+p.name+'</option>');
alreadyAdded.push(p);
}
}
}
// when docuemnt ready, populate the field
$(function(){
var field = $("#selOptions");
populateSearchProducts(dataArray, field);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="selOptions" />
updated based on comments

Related

How to loop over checked boxes and add to array

I am needing to loop over all of the checked check boxes of a specific name and add the values of that row to an array. My final array needs to look like this:
stmtData = {
sections: [
{ sectionCode: "AA", sectionName: "AA Test", amount: "33" },
{ sectionCode: "BB", sectionName: "BB Test", amount: "55" }
]
};
Looping over the checkboxes is the easy part:
var stmtData = [];
$.each($("input:checkbox[name='sectionElection']:checked"), function () {
// create sections array here
});
I'm getting the data like this, but there may be a better way?
stmtData["sectionCode"] = $(this).val();
stmtData["sectionName"] = $("#sectionElectionLbl_" + $(this).val()).text();
stmtData["amount"] = $("#sectionCost_" + $(this).val()).text();
You could improve it using map instead of each, bit rusty on jQuery but something like?
var stmtData = {}
stmtData.section = $("input:checkbox[name='sectionElection']:checked")
.map(function() {
var val = $(this).val();
var text = val.text();
return {
sectionCode: val,
sectionName = $("#sectionElectionLbl_" + text,
amount: text
}
});
Ok, I knew I had to use push somehow, figured it out and this works just fine.
var stmtData = [];
$.each($("input:checkbox[name='sectionElection']:checked"), function () {
// create sections array here
stmtData.push({
sectionCode: $(this).val(),
sectionName: $("#sectionElectionLbl_" + $(this).val()).text(),
amount: $("#sectionCost_" + $(this).val()).text()
});
});

Handsontable editing nested array

I am using handsontable and am having trouble getting the "beforeChange" and "afterChange" events to fire consistently, which I'm hoping use to commit updates to the database. I am using the following code (version 0.16.1):
HTML:
<div id="table"></div>
<div id="output"></div>
JavaScript:
var data = [{
id: 5,
name: 'Sedan',
price: 2000,
tags: ['pink', 'purple']
}, {
id: 6,
name: 'Truck',
price: 1500,
tags: ['green', 'blue']
}, {
id: 6,
name: 'SUV',
price: 1500,
tags: null
}];
var writeMessage = function(msg) {
var output = document.getElementById("output");
var div = document.createElement('DIV');
div.innerHTML = msg;
output.insertBefore(div, output.firstChild);
console.log(msg);
};
var tableDiv = document.getElementById("table");
this.table = new Handsontable(tableDiv, {
data: data,
colHeaders: ["id", "name", "price", "tags"],
columns: [{
data: "id"
}, {
data: "name"
}, {
data: "price"
}, {
data: "tags"
}],
beforeChange: function(changes, source) {
writeMessage("beforeChange: " + changes + ": " + source);
},
afterChange: function(changes, source) {
writeMessage("After Change fired: " + changes);
if (!changes) {
return;
}
var i, idx, key, newVal, modelID;
for (i = 0; i < changes.length; i++) {
idx = changes[i][0];
key = changes[i][1];
newVal = changes[i][3];
modelID = this.getDataAtRow(idx)[0];
writeMessage("New value: " + key + ": " + newVal);
}
}
});
http://codepen.io/anon/pen/GjzrdX?editors=0010
The event handlers fire when I'm editing the text and number fields and for the when tags are null, but do not fire for data objects with tag arrays (e.g. pink,purple; green,blue). How do I get the events to fire for the tag cells without modifying the data structure? Any advice would be greatly appreciated!
I believe that you are facing a bug here when trying to put an Array in a Cell but I cannot find anywhere in the handsontable documentation or any thread in their GitHub mentioning this issue... IMO, putting an Array in a Cell is suppose to be use as Source and not Data, which result in a cell that you can't edit (hence the events afterChange/beforeChange not triggered). In your example the third line is working because of the 'null' value which is not an Array.
Anyway, the only workaround I managed to do for you is to modify your data after you define your data structure (in order to respect your condition, but I strongly advice do modify them anyway because you will need to do that eventually).
Assuming that your tags can only contain two values :
var data1 = [];
for (var i=0; i<data.length;i++) {
if (data[i].tags != null) {
var temp = data[i].tags[0];
temp = temp.concat(',');
temp = temp.concat(data[i].tags[1]);
} else var temp = null;
data1.push({ id: data[i].id, name: data[i].name, price: data[i].price, tags: temp });
}
If the length of your Arrays tags can be more than that, just do a second loop to cover it.
See your code here with this solution implemented
You then can use data1 to load your table. If you need to save your data after modification, you can use a similar function to reverse it into your original data structure.

AngularJs Filter an array by another array

I have three arrays in a controller:
$scope.allUsers containing all users by :id and :name. E.g. smth like this.
$scope.job.delegated_to containing information related to job delegation. Looks like this.
$scope.job.delegated_to = [
{id: 5, user_id:33, user_name:"Warren", hour_count:4},
{id: 5, user_id:18, user_name:"Kelley", hour_count:2},
{id: 5, user_id:10, user_name:"Olson", hour_count:40},
{id: 5, user_id:42, user_name:"Elma", hour_count:2},
{id: 5, user_id:45, user_name:"Haley", hour_count:4},
{id: 5, user_id:11, user_name:"Kathie", hour_count:3}
]
$scope.freeUsers which has to contain all the users, not delegated to the job.
I added a watch
$scope.$watch('job.delegated_to.length', function(){
$scope.freeUsers = filterUsers( $scope.allUsers, $scope.job.delegated_to );
});
but have not been able to construct a working filter.
Your filterUsers function would be like:
var filterUsers = function(allUsers, jobs) {
var freeUsers = allUsers.slice(0); //clone allUsers
var jobUserIds = [];
for(var ind in jobs) jobUserIds.push(jobs[ind].user_id);
var len = freeUsers.length;
while(len--){
if(jobUserIds.indexOf(allUsers[len].id) != -1) freeUsers.splice(len, 1);
}
return freeUsers;
}
Checkout fiddle http://jsfiddle.net/cQXBv/
I would suggest using a library like Lo-Dash, which has many useful utility functions. You could then write your filter function as:
function filterUsers(allUsers, delegatedTo) {
var delegatedIndex = _.indexBy(delegatedTo, 'user_id');
return _.reject(allUsers, function(user) {return user.id in delegatedIndex});
}

angularjs ng-model and ng-select strange behaviour

I have a list of persons objects that I want to bind to a select element.
Controller implementation:
// Person controller
function PersonCtrl($scope) {
$scope.persons = [{id: 1, name: 'alex'}, {id: 2, name: 'jhon'}];
$scope.selectedPerson = {id: 2, name: 'jhon'};
}
Html markup:
<select ng-model="selectedPerson" ng-options="p.name for p in persons"></select>
The problem is that the binding seems to work only from the HTML to the scope and not the other way around. If I select an item from the drop down, it will correctly update the $scope.selectedPerson. But, if I initially set the value of the $scope.selectedPerson variable to one of the objects in the persons list, the value will not be reflected on the select control.
I also have fiddle that shows exactly what the problem is: http://jsfiddle.net/nE3gt/
Thank you in advance!
You need to set the selectedPerson to an element in the persons array, not a new object - otherwise Angular has no idea they are the same thing.
// Person controller
function PersonCtrl($scope) {
$scope.persons = [{id: 1, name: 'alexx'}, {id: 2, name: 'jhon'}];
$scope.selectedPerson = $scope.persons[1];
$scope.submit = function () {
//console.log(JSON.stringify($scope.Person));
$("#obj").text(JSON.stringify($scope.Person));
};
}
Updated fiddle: http://jsfiddle.net/nE3gt/2/
edit
If I'm understanding you correctly, you want to do something along these lines:
// Person controller
function PersonCtrl($scope) {
//serverData is the result of some http request...
var serverData = {persons: [{id: 1, name: 'alexx'}, {id: 2, name: 'jhon'}], selectedPerson: {id: 2, name: 'jhon'}};
$scope.persons = serverData.persons;
$scope.selectedPerson = null;
//find obj in persons that equals selectedPerson
for(var i = 0, l = serverData.persons.length; i < l; i++)
{
if(serverData.persons[i].id === serverData.selectedPerson.id)
{
$scope.selectedPerson = serverData.persons[i];
}
}
$scope.submit = function () {
//console.log(JSON.stringify($scope.Person));
$("#obj").text(JSON.stringify($scope.Person));
};
};
Even if your data comes back as different objects you need to make sure you're setting selectedPerson to an item that is in the persons array.
new fiddle: http://jsfiddle.net/nE3gt/4/
Set it to the index of the array you're binding to:
$scope.selectedPerson = $scope.persons[0];
Demo: http://jsfiddle.net/nE3gt/3/

creating list of objects in Javascript

Is it possible to do create a list of your own objects in Javascript? This is the type of data I want to store :
Date : 12/1/2011 Reading : 3 ID : 20055
Date : 13/1/2011 Reading : 5 ID : 20053
Date : 14/1/2011 Reading : 6 ID : 45652
var list = [
{ date: '12/1/2011', reading: 3, id: 20055 },
{ date: '13/1/2011', reading: 5, id: 20053 },
{ date: '14/1/2011', reading: 6, id: 45652 }
];
and then access it:
alert(list[1].date);
dynamically build list of objects
var listOfObjects = [];
var a = ["car", "bike", "scooter"];
a.forEach(function(entry) {
var singleObj = {};
singleObj['type'] = 'vehicle';
singleObj['value'] = entry;
listOfObjects.push(singleObj);
});
here's a working example http://jsfiddle.net/b9f6Q/2/
see console for output
Maybe you can create an array like this:
var myList = new Array();
myList.push('Hello');
myList.push('bye');
for (var i = 0; i < myList .length; i ++ ){
window.console.log(myList[i]);
}
Going off of tbradley22's answer, but using .map instead:
var a = ["car", "bike", "scooter"];
a.map(function(entry) {
var singleObj = {};
singleObj['type'] = 'vehicle';
singleObj['value'] = entry;
return singleObj;
});
Instantiate the array
list = new Array()
push non-undefined value to the list
var text = list.forEach(function(currentValue, currentIndex, listObj) {
if(currentValue.text !== undefined)
{list.push(currentValue.text)}
});
So, I'm used to using
var nameOfList = new List("objectName", "objectName", "objectName")
This is how it works for me but might be different for you, I recommend to watch some Unity Tutorials on the Scripting API.

Categories

Resources