0

I have simple code which allows me display related product based on tags, but I would like expand that code, that can I type more than one tag. At this moment I can run only:

<script type="text/javascript">category('tag1');</script>

And I got every product with 'tag1' in their tags. In this case name1 and name2.

var products = [
  {
    name: 'name1',
    tags: ['tag1', 'tag2', 'tag3'],
  },
  {
    name: 'name2',
    tags: ['tag1', 'tag3', 'tag4', 'tag5'],
  },
  {
    name: 'name3',
    tags: ['tag2', 'tag5', 'tag6'],
  }

];

var finalHtml = "";

function category(tag) {
  return products.filter(function(product){
    if (~product.tags.indexOf(tag)) {
      finalHtml += '<li>' + product.name + '</li>';
      document.getElementById("related_prod").innerHTML = finalHtml;
    }
  });
}

What I expect?

When I will run that code:

<script type="text/javascript">category('tag1, tag6');</script>

I would like see every product which has tag1 OR tag2 in their tags. In this case it should be name1 and name3.

6
  • This doesn't make much sense. name3 does not have tag1 in it, therefore if you are looking for products with tag1 AND tag2 in their tags, you will only get name1, not name3 Commented Jul 5, 2016 at 19:27
  • But have tag6, I would like to see product which have tag1 and tag6 in their tags. Name3 meets this condition. Commented Jul 5, 2016 at 19:44
  • But name1 doesn't? It's probably simply a typo in your question code and I understand now that you want to search using "AND" logic not "OR" but I would suggest editing and making sure there are no typos for the benefit of future readers. Commented Jul 5, 2016 at 19:50
  • 1
    Nevermind, it seems you did mean "OR" logic then. Commented Jul 5, 2016 at 20:04
  • 1
    You're right. It may be the fault of my poor knowledge of the language, so in the general context I have lost somewhere conditional operator. Commented Jul 5, 2016 at 20:05

2 Answers 2

1

Here is a solution using ECMAScript2015:

var products = [
  {
    name: 'name1',
    tags: ['tag1', 'tag2', 'tag3'],
  },
  {
    name: 'name2',
    tags: ['tag1', 'tag3', 'tag4', 'tag5'],
  },
  {
    name: 'name3',
    tags: ['tag2', 'tag5', 'tag6'],
  }
];

function category(...tags) {
    let related = document.getElementById("related_prod");
    // clear output
    related.innerHTML = '';
    // turn array values into object properties for faster lookup
    tags = tags.reduce((tags, tag) => (tags[tag] = 1, tags), {});
    // find products that have at least one of the tags 
    products.filter(product => product.tags.some(tag => tags[tag]))
            // display the names of the found products 
            .forEach(product => {
                let li = document.createElement('li');
                li.textContent = product.name;
                related.appendChild(li);
            });
}

category('tag4','tag5');
<ul id="related_prod"></ul>

Sign up to request clarification or add additional context in comments.

Comments

1

This can be mor generic as i understand from your requirement you wanted "OR" not "AND" so the answer can be :

function category() {
  var args = Array.prototype.slice.call(arguments);
  return products.filter(function(product){
    args.forEach(function(arg){   
     if (product.tags.indexOf(arg)> -1) {// readability 
       finalHtml += '<li>' + product.name + '</li>';
       document.getElementById("related_prod").innerHTML = finalHtml;
     }
  })
  });
}

Edit: For a better solution that have good seperation and readable one (assuming you are using ecmascript5 shim)

function findProducts(){
    var args = Array.prototype.slice.call(arguments);
    var foundProducts = [];
    products.forEach(function(product) {
         args.forEach(function(arg){  
            if(product.tags.indexOf(arg) > -1 && foundProdutcs.indexOf(product) == -1)
                foundProducts.push(product);
         }
    });
    return foundProducts;

}
function doSomethingWithTheProducts() {
   var products = findProducts.apply(this,arguments);
   var finalHtml = "";
   products.forEach(function(product){
       finalHtml += "<li>" + product.name + "</li">;
   });
   document.getElementById("related_prod").innerHTML = finalHtml;
}

doSomethingWithTheProducts('tag1','tag2');

2 Comments

It works almost perfectly. problem is the duplication position if it meets several conditions. Should I add keys to the list (which will not duplicate) and finally display the result? Is this a good solution for this problem?
this is actually not a good solution, you should split the search and generating html methods seperately. I will edit my answer for this now

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.