Delete specific element from array - javascript - javascript

I wanted to create small program where you enter the Book name and it's isbn code, with some other stuff, and it worked just fine until I wanted to create a prompt that asks me which book i want to delete (by it's ISBN). It actually works fine; when I write the isbn of the book that i stored in array, it deletes that book and it's isbn, but the alert is notifying me that the book does not exist in the database (not added previously) for every book I have stored.
For example, I have 5 books stored, one is (4th object in array) with "12121" ISBN code and I want to delete that one from the array. Function returns me false for first 3 objects in array (alert("Book with that ISBN doesn't exist in our database.")), then it returns true for the 4th object and then it returns me false also for the last object in array.
How do I make the function that only selects (and then deletes) object with ISBN that I put there in prompt box without checking every one of the objects inside the array?
var book = [];
book.push({
bookName: "GameOfThrones",
isbn: "12345",
});
function deleteBook(){
var book1 = prompt("Enter the ISBN of the book you want to delete");
for var(i=0; i<book.length; i++){
if (book[i].isbn == book1){
book.splice(i, 1);
alert("Book is successfully deleted");
}
else{
alert("Book with that ISBN doesn't exist in our database.");
}
}
for (var i=0; i<book.length; i++){
document.write(book[i].isbn + " - " + book[i].bookName + "<br/>");
}
}

If you choose to use an array of elements at random, then there is no getting around looking through each element. Your other option is to use a hash map or sort your array and use the binary search algorithm. Personally, I wouldn't bother with such premature optimization unless your Array is very very big (an order of a hundred thousand elements).
As an aside, your original code can be written in a much cleaner manner if you make use of the Array filter function.
var books = [];
books.push({
bookName: "GameOfThrones",
isbn: "12345",
});
var ISBNToDelete = prompt("Enter the ISBN of the book you want to delete");
function deleteBookByISBN(isbn, books) {
var newBooks = books.filter(function(book) {
return book.isbn !== isbn;
});
if (newBooks.length != books.length) {
alert("Book successfully deleted")
} else {
alert("Book with that ISBN doesn't exist in our database.");
}
return newBooks;
}
books = deleteBookByISBN(ISBNToDelete, books); // reassign the new set of books to books.

You could simply return from for statement at the moment you have found your book. The problem is when book is at the end of an array, in that case you would go trough whole array anyway.
Sorted array could help you a little bit (you would know approximately where to look for the book), but the best thing to do is to ditch the array and choose some kind of Hash table.
Easy implementation would be:
var books = {};
books['UniqueISBN'] = {name: "Where is the sun", author: "Unknown"};
Then you can delete it directly using delete;
var id = 'UniqueISBN';
delete books[id];

Easiest way with your example is to use break statement to stop processing of the for loop once you've found item:
function deleteBook(){
var book1 = prompt("Enter the ISBN of the book you want to delete");
for (var i=0,count=book.length; i<count; i++){
if (book[i].isbn == book1){
book.splice(i, 1);
alert("Book is successfully deleted");
break;
}
else{
alert("Book with that ISBN doesn't exist in our database.");
}
}
for (var i=0; i<book.length; i++){
document.write(book[i].isbn + " - " + book[i].bookName + "<br/>");
}
}
I don't know what browsers you're targeting, but if it's not IE you can eliminate the for loop and use Array.findIndex instead:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
Something like:
var index = book.findIndex(function (element) { return element.isbn == book1 });

If you filter on the array, you can return all the books that didn't match. During that process, you can store a boolean if the book was found. Using that boolean, you can perform other actions (like deleting it from the database).
You could perform those database actions inside the filter, but to keep code easier to follow and maintain, it's good to separate it. Which is why there's an if-block after the filter.
This following example demonstrates this concept above. It also uses a textarea for the logging, as opposed to the console. This is meant to serve as a demonstration on how to output to an HTML element using the textContent property.
Example:
document.addEventListener("DOMContentLoaded", onLoad);
var books = [{
bookName: "GameOfThrones",
isbn: "12345"
}, {
bookName: "Jurrasic Park",
isbn: "98765"
}, {
bookName: "Westworld",
isbn: "33333"
}];
function deleteBook(isbn) {
// use isbn passed in, or look it up
isbn = isbn || document.getElementById('isbn').value;
var book_found = false;
books = books.filter((book, i) => {
if (book.isbn == isbn) {
book_found = true;
debug.textContent += `Deleting "${book.bookName} from database...\n`;
return false;
} else
return isbn != book.isbn;
});
// handle any follow-up actions
if (book_found) {
debug.textContent += `New List (w/o ${isbn}):\n`;
outputBooks(books);
} else
debug.textContent += `Book (isnb:${isbn}) could not be found!\n\n`;
}
// Used for Logging Output (in place of console)
function outputBooks(books) {
books.forEach(book => {
debug.textContent += [' ' + book.isbn, book.bookName].join(': ') + '\n'
});
debug.textContent += '\n';
}
// Ensures the debug element is on the page
function onLoad(event) {
// Default
window.debug = document.getElementById('debug');
debug.textContent += 'Starting List:\n';
outputBooks(books);
}
textarea {
height: 20em;
width: 80%;
display: block;
}
.block {
display: block;
}
<label>ISBN:
<input id="isbn" type="text" />
</label>
<button type="button" class="delete" onclick="deleteBook()">Delete</button>
<label><span class="block">Debug:</span>
<textarea id="debug" disabled></textarea>
</label>

Related

How to get inner array in javascript

I'm trying to get all the contents from an array.
This is the function that extracts the data for display via innerHTML:
window.location.href = 'gonative://contacts/getAll?callback=contacts_callback';
function contacts_callback(obj) {
var contactinfo = obj.contacts.map(({givenName}) => givenName) + " " +
obj.contacts.map(({familyName}) => familyName) + " " + " (" +
obj.contacts.map(({organizationName}) => organizationName) + ") " +
obj.contacts.map(({phoneNumbers.phoneNumber}) => phoneNumbers.phoneNumber) + "<br>";
document.getElementById("demo").innerHTML = contactinfo;
}
This is an example of what the input looks like when there are only 2 contacts:
{"success":true,"contacts":[
{
"emailAddresses":[],
"phoneNumbers":
[
{
"label":"unknown",
"phoneNumber":"XXX-XXXXXXX"
}
],
"givenName":"John",
"organizationName":"Apple",
"familyName":"Appleseed",
},
{
"emailAddresses":[],
"phoneNumbers":
[
{
"label":"unknown",
"phoneNumber":"XXX-XXXXXXX"
}
],
"givenName":"John",
"organizationName":"Apple",
"familyName":"Appleseed",
},
]
}
I just want the result to be listed as:
John Appleseed (Apple) XXX-XXXXXXX
John Appleseed (Apple) XXX-XXXXXXX
Two issues:
You are displaying all given names, then all family names, ...etc, each with a separate .map() call. Instead only perform one .map() call on the array and then display the properties for each iterated object.
phoneNumbers.phoneNumber is not a correct reference. phoneNumbers is an array, so you should iterate it.
Also:
Template literals make it maybe a bit easier to build the string
You can use .join("<br>") to glue the lines together with line breaks.
Here is a corrected version:
function contacts_callback(obj) {
var contactinfo = obj.contacts.map(o =>
`${o.givenName} ${o.familyName} (${o.organizationName}) ${
o.phoneNumbers.map(n => n.phoneNumber)
}`)
.join("<br>");
document.getElementById("demo").innerHTML = contactinfo;
}
// Demo
var obj = {"success":true,"contacts":[{"emailAddresses":[],"phoneNumbers":[{"label":"unknown","phoneNumber":"XXX-XXXXXXX"}],"givenName":"John","organizationName":"Apple","familyName":"Appleseed",},{"emailAddresses":[],"phoneNumbers":[{"label":"unknown","phoneNumber":"XXX-XXXXXXX"}],"givenName":"John","organizationName":"Apple","familyName":"Appleseed",},]};
contacts_callback(obj);
<div id="demo"></div>
It is hard to give an answer since is hard to tell what you can have in your phoneNumbers array and if you will also display one line for each phone number in that array.
I'll do something like this:
function contacts_callback(obj) {
let arrayContacts = [];
// Iterate over all your contacts
obj.contacts.forEach(item => {
// Iterate over each contact's phone numbers
item.phoneNumbers.forEach(phone => {
// Building your string with string interpolation and pushing to result array
// You could also add <br> or other tags needed here
arrayContacts.push(`${item.givenName} ${item.familyName} (${item.organizationName}) ${phone.phoneNumber}`);
});
});
// Return your array, use it in your innerHTNL, etc.
return arrayContacts;
}
If Your obj is called "obj", than:
const result = obj.contacts.map(contact =>{
return `${contact.givenName} ${contact.familyName} (${contact.organizationName}) ${contact.phoneNumbers[0].phoneNumber}`
}
this code will give back an array of informations that U asked, but if user has more than 1 phone number, it will take only first from the list

Improve loop over nested properties - javascript

Trying to filter students according to a nested property value.
Basically each student object has property of type array : studentSuperSubject
which in turn has array as a property as well : studentSubSubjectOrSkill
subjects is array of objects in the following form:
{superSubject: "some super subject name", subSubject: "some sub subject name"}.
each subSubject inside studentSubSubjectOrSkill has the property studentSubSubjectScore which is the one I'm looking for.
I want to loop over the students array for each subject in subjects and create and object i then store to another array - grades=[]
I manage to get it done with what looks like a Hugh bawl of spaghetti code:
for (let subject of subjects) {
var grades = [];
this.data.students.filter(student => {
let name = student.studentName;
// loop over each student > superSubject > subSubject
for (let superSubject of student.studentSuperSubject) {
if (superSubject.superSubjectName === subject.superSubject) {
superSubject.studentSubSubjectOrSkill.filter(sub => {
if (sub.subSubjectName === subject.subSubject) {
grades.push({
name: name,
pass: sub.studentSubSubjectScore > 58
});
return;
}
});
}
}
});
subject["grades"] = grades;
}
Any idea how can I improve that to make life easier for the future developers which are going to use this code?
as a side note, lodash is available in this project
thanks.
1/ You have improper use of filter that should be used when you want to return subset of the array, you should use map when you want to execute an action for each element of the array
2/ for... of ... is for iterating over the values, for... in... over the properties
3/ I think it is more readable like this:
for (let subject of subjects) {
var grades = [];
this.data.students.map(student => {
let name = student.studentName;
student.studentSuperSubject
.filter(superSubject => superSubject.superSubjectName === subject.superSubject)
.map(superSubject=> {
superSubject.studentSubSubjectOrSkill
.filter(sub => sub.subSubjectName === subject.subSubject)
.map(sub=>{
grades.push({
name: name,
pass: sub.studentSubSubjectScore > 58
});
});
});
});
subject["grades"] = grades;
}
For readability, I would check one thing at a time and add some comments.
// Iterates for all subjects.
subjects.forEach(subject => {
// Subject grades.
subject.grades = [];
// Iterates for all the students.
students.forEach(student => {
// Finds and validates the student super subject.
var studentSuperSubject = student.studentSuperSubject.find(superSubject => superSubject.superSubjectName === subject.superSubject);
if (!studentSuperSubject) return;
// Finds and validates the student sub subject.
var studentSubSubject = studentSuperSubject.studentSubSubjectOrSkill.find(subSubject => subSubject.subSubjectName == subject.subSubject);
if (!studentSubSubject) return;
// Saves the student grade.
subject.grades.push({
name: student.studentName,
pass: studentSubSubject.studentSubSubjectScore > 58
});
});
});

Group objects in array by property

I have just started to pick up coding seriously. :)
I came across a problem that seems too complicated for me.
How to group the following products by promotions type?
var data = [
{
name:'product1',
price:'40',
promotion:[
{
name:'Buy 3 get 30% off',
code:'ewq123'
},
{
name:'Free Gift',
code:'abc140'
}
]
},
{
name:'product2',
price:'40',
promotion:[
{
name:'Buy 3 get 30% off',
code:'ewq123'
}
]
},
{
name:'product3',
price:'40',
promotion:[
{
name:'Buy 3 get 30% off',
code:'ewq123'
}
]
},
{
name:'product4',
price:'40'
},
{
name:'product5',
price:'40',
promotion:[
{name:'30% off', code:'fnj245'}
]
},
{
name:'product6',
price:'0',
promotion:[
{
name:'Free Gift',
code:'abc140'
}
]
}
];
I would like to get result in the following format
result =[
{
name : 'Buy 3 get 30% off',
code: 'ewq123',
products: [
... array of products
]
},
{
name : '30% off',
code: 'fnj245',
products: [
... array of products
]
},
{
...
}
];
I am able to get a list of products by promotion code, but how can I make it generic?
function productHasPromo(product, promotion){
if(!product.hasOwnProperty('promotion')) return false;
var productPromo = product.promotion;
for(var i=0; i<productPromo.length; i++){
if(productPromo[i].code === promotion){
return true;
}
}
return false;
}
function groupProductByPromo(products, promotion){
var arr = [];
for(var i=0; i<products.length; i++){
if(productHasPromo(products[i], promotion)){
arr.push(products[i]);
}
}
return arr;
}
Explanation
You could write a function that loops through your array and search for the unique values within a specified property. That is easily done when working with simple data types, but can be done with more complex structures as arrays of objects (like in your example), using a helper grouping function.
Since you also need the output to be in a specific format after the grouping, we will have to work on a transformer also. This transformer will receive the original data and the unique values extracted by the grouping function, and will generate the desired output.
The following functions were used in the example:
Array.prototype.groupBy = function (property, grouping, transformer) {
var values = [];
this.forEach(function (item) {
grouping.call(this, item, property).forEach(function (item) {
if (!values.contains(property, item[property])) {
values.push(item);
}
});
});
return transformer.call(this, values);
};
Array.prototype.contains = function (key, value) {
return this.find(function (elm) {
return elm[key] === value;
});
};
function transformerFunction(values) {
this.forEach(function (item) {
if (!item.promotion) return;
item.promotion.forEach(function (promotion) {
values.forEach(function (option) {
if (option.code === promotion.code) {
if (option.products) {
option.products.push(item);
} else {
option.products = [item];
}
}
});
});
});
return values;
}
function groupingFunction(item, property) {
if (!item.promotion) return [];
var values = [];
item.promotion.forEach(function (promotion) {
if (!values.contains(property, promotion[property])) {
values.push(promotion);
}
});
return values;
}
Usage as follows:
var items = data.groupBy('code', groupFunction, transformFunction);
Example
Check the example i've prepared at jsfiddle
Welcome to the coding world. A lot of people start off with a problem by trying to write some code, then they wonder why it doesn't work and scratch their heads, don't know the basics of debugging it, and then post here to SO. They're missing the crucial first step in programming which is to figure out how you are going to do it. This is also called designing the algorithm. Algorithms are often described using something called pseudo-code. It has the advantage that it can be looked at and understood and established to do the right thing, without getting bogged down in all the mundane details of a programming language.
There are some algorithms that are figured out by some very smart people--like the Boyer-Moore algorithm for string matching--and then there are other algorithms that programmers devise every day as part of their job.
The problem with SO is that all too often someone posts a question which essentially about an algorithm, and then all the keyboard-happy code jockeys pounce it and come up with a code fragment, which in many cases is so contorted and obtuse that one cannot even see what the underlying algorithm is.
What is the algorithm you propose for solving your problem? You could post that, and people would probably give you reasonable comments, and/or if you also give an actual implementation that doesn't work for some reason, help you understand where you've gone wrong.
At the risk of robbing you the pleasure of devising your own algorithm for solving this problem, here's an example:
Create an empty array for the results.
Loop through the products in the input.
For each product, loop through its promotions.
Find the promotion in the array of results.
If there is no such promotion in the array of results, create a new one, with an empty list of products.
Add the product to the array of products in the promotion entry in the array.
In pseudo-code:
results = new Array // 1
for each product in products (data) // 2
for each promotion in promotions field of product // 3
if results does not contain promotion by that name // 4
add promotion to results, with empty products field // 5
add product to products field of results.promotion // 6
If we believe this is correct, we can now try writing this in JavaScript.
var result = []; // 1
for (var i = 0; i < data.length; i++) { // 2
var product = data[i];
var promotions = product.promotion;
for (var j = 0; j < promotions.length; j++) { // 3
var promotion = promotions[i];
var name = promotion.name;
var result_promotion = find_promotion_by_name(name);
if (!result_promotion) { // 4
result_promotion = { name: name, products: [], code: promotion.code };
result.push(result_promotion); // 5
}
result_promotion.products.push(name); // 6
}
}
This code is OK, and it should get the job done (untested). However, it is still a bit unreadable. It does not follow the pseudo-code very closely. It somehow still hides the algorithm. It is hard to be sure that it is completely correct. So, we want to rewrite it. Functions like Array#foreach make it easier to do this. the top level can simply be:
var result = [];
data.forEach(processProduct);
In other words, call the processProduct function for each element of data (the list of products). It will be very hard for this code to be wrong, as long as `processProduct is implemented incorrectly.
function processProduct(product) {
product.promotion.forEach(processPromotion);
}
Again, this logic is provably correct, assuming processPromotion is implemented correctly.
function processPromotion(promotion) {
var result_promotion = getPromotionInResults(promotion);
result_promotion.products.push(name);
}
This could hardly be clearer. We obtain the entry for this promotion in the results array, then add the product to its list of products.
Now we need to simply implement getPromotionInResults. This will include the logic to create the promotion element in the results array if it doesn't exist.
function getPromotionInResults(promotion) {
var promotionInResults = findPromotionInResultsByName(promotion.name);
if (!promotionInResults) {
promotionInResults = {name: promotion.name, code: promotion.code, products: []};
result.push(promotionInResults);
}
return promotionInResults;
}
This also seems demonstrably correct. But we still have to implement findPromotionInResultsByName. For that, we can use Array#find, or some equivalent library routine or polyfill:
function findPromotionInResultsByName(name) {
return result.find(function(promotion) {
return promotion.name === name;
});
}
The entire solution is thus
function transform(data) {
// Given a product, update the result accordingly.
function processProduct(product) {
product.promotion.forEach(processPromotion);
}
// Given a promotion, update its list of products in results.
function processPromotion(promotion) {
var result_promotion = getPromotionInResults(promotion);
result_promotion.products.push(name);
}
// Find or create the promotion entries in results.
function getPromotionInResults(promotion) {
var promotionInResults = findPromotionInResultsByName(promotion.name);
if (!promotionInResults) {
promotionInResults = {name: promotion.name, code: promotion.code, products: []};
result.push(promotionInResults);
}
return promotionInResults;
}
// Find an existing entry in results, by its name.
function findPromotionInResultsByName(name) {
return result.find(function(promotion) {
return promotion.name === name;
});
}
var result = [];
data.forEach(processProduct);
return result;
}
Ok, after a few hours of works, with lots of help online and offline, I finally made it works. Thanks for the people who has helped.
Please do comment if you have a more elegant solution, always love to learn.
For people who ran into similar problem:
Here is my solution
function groupProductsByPromo(data){
var result = [];
// filter only product with promotion
var productsWithPromo = data.filter(function(product){
return product.hasOwnProperty('promotions');
});
// create promotions map
var mappedProducts = productsWithPromo.map(function(product) {
var mapping = {};
product.promotions.forEach(function(promotion) {
mapping[promotion.code] = {
promotion: promotion
};
});
return mapping;
});
// reduce duplicates in promotion map
mappedProducts = mappedProducts.reduce(function(flattenObject, mappedProducts) {
for (var promoCode in mappedProducts) {
if (flattenObject.hasOwnProperty(promoCode)) {
continue;
}
flattenObject[promoCode] = {
code: promoCode,
name: mappedProducts[promoCode].promotion.name
};
}
return flattenObject;
}, {});
// add products to promo item
for(var promoCode in mappedProducts){
mappedProducts[promoCode].products = productsWithPromo.filter(function(product){
return product.promotions.some(function(promo){
return promo.code === promoCode;
});
});
result.push(mappedProducts[promoCode]);
}
return result;
}
Check out lodash - a nifty library for doing all sorts of transforms.
lodash.groupBy is what you're looking for.

How to get/filter all results from JSON file with underscore.js

I have this (shortened for question) JSON file:
[
{
"product":"aardappelen gebakken",
"quantity":"100gr",
"carbohydrates":"19,3"
},
{
"product":"aardappelen pikant",
"quantity":"100gr",
"carbohydrates":"3"
},
{
"product":"aardappelmeel",
"quantity":"100gr",
"carbohydrates":"80"
}
]
Wat i want to do is:
search for a product, and result all of its content, like when i would search for "aardappelmeel", i get product, quantity and carbohydrates key value, i do this with this code:
the search term is hardcoded for the moment, this will be a var later one.
$(function() {
$.getJSON( "js/data.json").fail(function(jqxhr, textStatus, error) {
var err = textStatus + ", " + error;
console.log( "Request Failed: " + err );
}).done(function(data) {
var carbohydratesResult = getCarbohydrates(data, 'aardappelmeel');
console.log(carbohydratesResult);
});
});
function getCarbohydrates(arr, searchTerm){
var result;
if(searchTerm === '') {
result = 'No searchterm';
}
else {
result = _.where(arr, {product: searchTerm});
}
return result;
}
This gets 1 result:
Question: When i search for "aardappelen", i get no result, and it should be 2, because there are 2 products that contain the name "aardappelen". How do i do this?
I use jQuery, Underscore. If Underscore is not needed for this, fine by me, please show me how i modify my code to get more then one result when "product" value contains the search term.
You need _.filter along with indexOf to do a substring search:
result = _.filter(arr, function(item) {
return item.product && item.product.indexOf(searchTerm) != -1;
});
Note that _.where performs an exact match.
I would probably say underscore is not needed for this (not optimal to include an entire js library just use use a single function). Searching for text simply in JavaScript is never fun. You're probably best writing some regex function that loops over your result set and tries to match some text.
If possible, I would try to implement the searching functionality on the server side, and return those results in an ajax request.
Rough example of a JS Solution...
var searchText = 'blah',
matches = [];
for(var i = 0; i < results.length; i++) {
var reg = new RegExp(searchText);
if(results[i].product.match(reg)) matches.push(results[i]);
}
return matches;

Backbone.js - Filter a Collection based on an Array containing multiple keywords

I'm using Backbone.js/Underscore.js to render a HTML table which filters as you type into a textbox. In this case it's a basic telephone directory.
The content for the table comes from a Collection populated by a JSON file.
A basic example of the JSON file is below:
[{
"Name":"Sales and Services",
"Department":"Small Business",
"Extension":"45446",
},
{
"Name":"Technical Support",
"Department":"Small Business",
"Extension":"18800",
},
{
"Name":"Research and Development",
"Department":"Mid Market",
"Extension":"75752",
}]
I convert the text box value to lower case and then pass it's value along with the Collection to this function, I then assign the returned value to a new Collection and use that to re-render the page.
filterTable = function(collection, filterValue) {
var filteredCollection;
if (filterValue === "") {
return collection.toJSON();
}
return filteredCollection = collection.filter(function(data) {
return _.some(_.values(data.toJSON()), function(value) {
value = (!isNaN(value) ? value.toString() : value.toLowerCase());
return value.indexOf(filterValue) >= 0;
});
});
};
The trouble is that the function is literal. To find the "Sales and Services" department from my example I'd have to type exactly that, or maybe just "Sales" or "Services". I couldn't type "sal serv" and still find it which is what I want to be able to do.
I've already written some javascript that seems pretty reliable at dividing up the text into an array of Words (now updated to code in use).
toWords = function(text) {
text = text.toLowerCase();
text = text.replace(/[^A-Za-z_0-9#.]/g, ' ');
text = text.replace(/[\s]+/g, ' ').replace(/\s\s*$/, '');
text = text.split(new RegExp("\\s+"));
var newsplit = [];
for (var index in text) {
if (text[index]) {
newsplit.push(text[index]);
};
};
text = newsplit;
return text;
};
I want to loop through each word in the "split" array and check to see if each word exists in one of the key/values. As long as all words exist then it would pass the truth iterator and get added to the Collection and rendered in the table.
So in my example if I typed "sal serv" it would find that both of those strings exist within the Name of the first item and it would be returned.
However if I typed "sales business" this would not be returned as although both the values do appear in that item, the same two words do not exist in the Name section.
I'm just not sure how to write this in Backbone/Underscore, or even if this is the best way to do it. I looked at the documentation and wasn't sure what function would be easiest.
I hope this makes sense. I'm a little new to Javascript and I realise I've dived into the deep-end but learning is the fun part ;-)
I can provide more code or maybe a JSFiddle if needed.
Using underscore's any and all make this relatively easy. Here's the gist of it:
var toWords = function(text) {
//Do any fancy cleanup and split to words
//I'm just doing a simple split by spaces.
return text.toLowerCase().split(/\s+/);
};
var partialMatch = function(original, fragment) {
//get the words of each input string
var origWords = toWords(original + ""), //force to string
fragWords = toWords(fragment);
//if all words in the fragment match any of the original words,
//returns true, otherwise false
return _.all(fragWords, function(frag) {
return _.any(origWords, function(orig) {
return orig && orig.indexOf(frag) >= 0;
});
});
};
//here's your original filterTable function slightly simplified
var filterTable = function(collection, filterValue) {
if (filterValue === "") {
return collection.toJSON();
}
return collection.filter(function(data) {
return _.some(_.values(data.toJSON()), function(value) {
return partialMatch(value, filterValue);
});
});
};
Note: This method is computationally pretty inefficient, as it involves first looping over all the items in the collection, then all the fields of each item, then all words in that item value. In addition there are a few nested functions declared inside loops, so the memory footprint is not optimal. If you have a small set of data, that should be OK, but if needed, there's a number of optimizations that can be done. I might come back later and edit this a bit, if I have time.
/code samples not tested

Categories