Reputation: 766
I am trying to build a 3-tiered function: First, an array lists available workshops (array is called 'workshops'). Second, another array lists workshops that a user has selected (this array is called 'selectedWorkshops'). Third, I have a final array called 'registeredWorkshops'.
When my function is run, I want objects within 'selectedWorkshops' to be added to 'registeredWorkshops', then I want to delete any objects within 'selectedWorkshops' from both 'selectedWorkshops' and any matching elements from 'workshops'. So, where those objects used to exist in both 'selectedworkshops' and 'workshops', now they only exist in 'registeredWorkshops'.
Here's what I've got so far:
addRemoveWorkshops = function(){
var numberOfWorkshops = selectedWorkshops.length;
for(var i = 0; i < numberOfWorkshops; i++ ){
registeredWorkshops.push(selectedWorkshops[i]);
for(var j = 0, arrayLength = workshops.length; j < arrayLength; j++) {
var searchTerm = selectedWorkshops[i].WorkshopId;
if (workshops[j].WorkshopId === searchTerm) {
workshops = workshops.slice(j);
}
}
selectedWorkshops = selectedWorkshops.slice(i);
}
};
addRemoveWorkshops();
However, the function doesn't appear to work properly. It doesn't seem to be deleting the correct workshops, and it only seems to add one of the selectedWorkshops to registeredWorkshops. What am I doing wrong?
Here's a codepen demonstration: http://codepen.io/trueScript/pen/GgVWMx
Upvotes: 2
Views: 77
Reputation: 6394
A while
loop + a for
one :
var workshops = [{
name: 'apples',
WorkshopId: '19'
}, {
name: 'oranges',
WorkshopId: '3b'
}, {
name: 'pears',
WorkshopId: 'x6'
}, {
name: 'pineapples',
WorkshopId: '55'
}, {
name: 'watermelons',
WorkshopId: '8v'
}];
var selectedWorkshops = [{
name: 'oranges',
WorkshopId: '3b'
}, {
name: 'watermelons',
WorkshopId: '8v'
}, {
name: 'pears',
WorkshopId: 'x6'
}];
var registeredWorkshops = [];
var numberOfWorkshops;
addRemoveWorkshops = function () {
numberOfWorkshops = selectedWorkshops.length;
// A single while statment is enough and lighter
while (selectedWorkshops.length) {
var removedWorkshop;
numberOfWorkshops = registeredWorkshops.push(selectedWorkshops[0]);
for (var i = 0; i < workshops.length; i++)
if (workshops[i].WorkshopId == selectedWorkshops[0].WorkshopId) {
workshops.splice(i, 1);
break;
}
selectedWorkshops.splice(0, 1);
}
};
addRemoveWorkshops();
// Better for viewing the content (in firefox I have just "Object") :
console.log("workshops : ");
for (var i = 0; i < workshops.length; i++)
console.log('- ' + workshops[i].name);
console.log("selectedWorkshops : ");
for (var i = 0; i < selectedWorkshops.length; i++)
console.log('- ' + selectedWorkshops[i].name);
console.log("registeredWorkshops : ");
for (var i = 0; i < registeredWorkshops.length; i++)
console.log('- ' + registeredWorkshops[i].name);
Upvotes: 1
Reputation: 29999
If it's not possible to add other properties to the objects (as per my other answer) then I'd tackle it like this:
function registration(workshops, selected, registered) {
// add the selected workshops to registered
selected.forEach(function(workshop) {
registered.push(workshop);
});
// remove them from the other lists
registered.forEach(function(workshop) {
removeWorkshop(selected, workshop);
removeWorkshop(workshops, workshop);
});
}
function removeWorkshop(list, workshop) {
var index = list.indexOf(workshop);
if(index >= 0) {
list.splice(index, 1);
}
}
The function expects each of the arrays to be passed in as arguments and it will modify them in place. Things always become clearer and easier to test if you move your loops out into functions before nesting them.
There should be no reason not to use the indexOf
method here, as it saves you having to write an extra loop. However, if for some reason you needed to use the WorkshopId
property to locate the item within the list, you could create another helper method to do this for you.
function findWorkshop(list, workshop) {
for(var i = 0; i < list.length; i++) {
if(list[i].WorkshopId === workshop.WorkshopID) {
return i;
}
}
return -1;
}
Then you just amend the removeWorkshop
function to reflect that.
function removeWorkshop(list, workshop) {
var index = findWorkshop(list, workshop);
list.splice(index, 1);
}
Upvotes: 2
Reputation: 29999
I think it would be easier to slightly rethink your data structure. If you go for the imperative solution above, you run this risk of ending up with duplicate values in more than one list.
Would it not be easier to add registered
and selected
properties to your workshop objects?
var workshops = [
{
name: 'apples',
WorkshopId: '19',
registered: true,
selected: false
},
{
name: 'oranges',
WorkshopId: '3b',
selected: true,
registered: false
},
// ...
];
Then if you need to be able to get a list of all the registered workshops, you can create it using a filter.
// helper function for filtering based
// on a given property
function property(name) {
return function(object) {
return object[name];
}
}
var registered = workshops.filter(property('registered'));
var selected = workshops.filter(property('selected'));
To select a workshop, all you need to do is change the select property to true:
workshops[3].selected = true;
You could then write the original function to register all workshops that were selected like this:
function registration(workshops) {
workshops.forEach(function(workshop) {
if(workshop.selected) {
workshop.registered = true;
workshop.selected = false;
}
});
}
Upvotes: 2
Reputation: 708
addRemoveWorkshops = function(){
var numberOfWorkshops = selectedWorkshops.length;
for(var i = 0; i < numberOfWorkshops; i++ ){
registeredWorkshops.push(selectedWorkshops[i]);
for(var j = 0, arrayLength = workshops.length; j < arrayLength; j++) {
var searchTerm = selectedWorkshops[i].WorkshopId;
if (workshops[j].WorkshopId === searchTerm) {
workshops = workshops.splice(j,1);
}
}
selectedWorkshops = selectedWorkshops.splice(i,1);
}
};
Upvotes: 0