2

Can anyone help me with this? Note: Project is a dynamic Webflow website, so the entries get generated as described below, I can only change class names

Let's say I have multiple items I want to append to a select field

<div class="item-category">Kitchen</div>
<div class="actual-item">Spoon</div>
<div class="item-category">Living room</div>
<div class="actual-item">Sofa</div>
<div class="item-category">Kitchen</div>
<div class="actual-item">Plate</div>

I'm able to append items using actual-item class

$('.actual-item').each(function(){
var s=$(this).text();
$('.item-select-field').append('<option value="'+s+'">'+s+'</option>');
})

But I want to have option value equal to corresponding item-category (so I could filter items out later). Is there any way to do this? I've thought of changing the item-category class to actual-item and then using only even elements as option-value but I don't know to do this.

Fico
  • 33
  • 5
  • `.prev()`. Or of you can change HTML, put value as `data-item-category="Kitchen">Plate` – Justinas May 14 '21 at 06:47
  • Build your html with the data you need: `
    Sofa
    TV
    ` *or* group your data hierarchically - `
    Kitchen
    Spoon
    Fork
    ` (or use nested `ul`/`li`)
    – freedomn-m May 14 '21 at 06:56
  • If your `option value=` matches the category, then the end result will be a number of `option`s with the same `value=` - which really won't help you in the long run. Use `data-` attributes liberally. – freedomn-m May 14 '21 at 07:08
  • @freedomn-m I can't add `data-category` because it's a dynamic Webflow website, entries get generated as in the description, I might be able to nest `actual-item` in the `item-category` but I still don't know where to go from there – Fico May 14 '21 at 07:15
  • Always useful to add in the question that your source (html) is from a third-party that you can't change. 99% of the time it's better to change the source rather than try to manipulate it post-render. But if you can't, you can't. Or at least state how much you *can* change as it looks like you can change classes? I have no idea what you mean by "a dynamic webflow website" – freedomn-m May 14 '21 at 07:17
  • "*I've thought of changing the item-category class to actual-item and then using only even elements*" - [here's how to select only odd/even items](https://stackoverflow.com/questions/30526230/how-to-add-odd-and-even-classes-to-divs-jquery), though updating your markup to more clearly identify the relationships seems safer, if that's possible. – Don't Panic May 14 '21 at 07:19

4 Answers4

0

As your HTML will always be category followed by item, you can find the items then use .prev() to get the previous div which contains the category:

var category = $(this).prev().text()

As the requirement is "so I could filter items out later" - you don't want to set the value= to category otherwise you get multiple options with the same value, so you don't know which one was selected

<option value="Kitchen">Spoon</option>
<option value="Kitchen">Plate</option>

instead, you can add a data- attribute to the <option>

<option data-category="Kitchen">Spoon</option>
<option data-category="Kitchen">Plate</option>

then you can use this to filter the options later, eg:

$(".item-select-field :not([data-category='Kitchen'])").hide()

Giving:

$('.actual-item').each(function() {
  var val = $(this).text();
  var cat = $(this).prev().text();
  $('.item-select-field').append('<option value="' + val + '" data-category="' + cat + '">' + cat + ":" + val + '</option>');
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item-category">Kitchen</div>
<div class="actual-item">Spoon</div>
<div class="item-category">Living room</div>
<div class="actual-item">Sofa</div>
<div class="item-category">Kitchen</div>
<div class="actual-item">Plate</div>

<select class='item-select-field'>
</select>

You could equally get each category and use .next() to get the item for that category, which ever makes the most sense to you.

$('.item-category').each(function() {
  var cat = $(this).text();
  var val = $(this).next().text();
  $('.item-select-field').append('<option value="' + val + '" data-category="' + cat + '">' + cat + ":" + val + '</option>');
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item-category">Kitchen</div>
<div class="actual-item">Spoon</div>
<div class="item-category">Living room</div>
<div class="actual-item">Sofa</div>
<div class="item-category">Kitchen</div>
<div class="actual-item">Plate</div>

<select class='item-select-field'>
</select>
freedomn-m
  • 27,664
  • 8
  • 35
  • 57
  • 1
    Thank you so much! This is what I couldn't figure out `var category = $(this).prev().text()` – Fico May 14 '21 at 08:00
  • on a side note, is it possible to use something else instead of value in the code below? Filtering works great with `this.value`, but it doesn't work if I switch it with `this.data-category` for example. `$(function() { $('#select-item').on('change', function() { var itemVal= this.value; $('#select-secondItem option').hide().filter(function() { return this.value.indexOf(itemVal) === 0; }) .show(); }) .change(); });` – Fico May 14 '21 at 10:39
  • Change `this.value.indexOf(itemVal) === 0` to `$(this).data("category") === itemVal` – freedomn-m May 14 '21 at 10:43
  • I'm getting reference error for `itemVal=this.data-category` I've tried with `itemVal=this.data("category")` but didn't work – Fico May 14 '21 at 10:58
  • Don't mix up `=` with `==` – freedomn-m May 14 '21 at 11:00
  • No code error with `var itemVal=$(this).data("category");` but filtering doesn't work – Fico May 14 '21 at 11:32
  • You should be comparing `itemVal` with `.data("category")` - not setting it. Your code was `$('#select-secondItem option').hide().filter(function() { return this.value.indexOf(itemVal) === 0; })` but should/could be `$('#select-secondItem option').hide().filter(function() { return $(this).data("category") === itemVal; })` - why are you changing `var itemVal =`? – freedomn-m May 14 '21 at 11:36
  • 1
    I suggest you ask a new question (can link to it from here) where you'll be able to provide a complete code snippet that's well formatted. Answer comments aren't the best place for this. – freedomn-m May 14 '21 at 11:37
  • 1
    https://stackoverflow.com/questions/67534135/modify-filter-function-for-select-options-in-jquery – Fico May 14 '21 at 12:11
  • See, makes much more sense in your new question. I assumed you were matching category *value* to item data-category, but there's no need to and you can match data- to data-. – freedomn-m May 14 '21 at 13:15
  • thanks a lot man, you really helped me out! – Fico May 14 '21 at 13:18
0

This answer is based off here.

Use this format: new Option("option text", "value");

$('.actual-item').each(function(){
    var s = $(this).text();
    var o = new Option(s, s);
    
    $(".item-select").append(o);
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="item-category">Kitchen</div>
<div class="actual-item">Spoon</div>
<div class="item-category">Living room</div>
<div class="actual-item">Sofa</div>
<div class="item-category">Kitchen</div>
<div class="actual-item">Plate</div>

<select class="item-select">
</select> 
Prosy Arceno
  • 2,616
  • 1
  • 8
  • 32
0

If I understand your question correctly I believe this is the effect you're trying to achieve.

I've gathered all of the items and their parent categories and used the optgroup element to group them inside of the select.

I've also modified your HTML slightly so the relationship between category and item is more obvious inside the markup.

$('.actual-item').each(function(){
  const option = $(this).text();
  const optgroup = $(this).parent().find('.category-title').text();
  
  if ($(`[label="${optgroup}"]`).length) {
    $(`[label="${optgroup}"]`).append(`<option value="${option}">${option}</option>`);
  } else {
    $('.item-select-field').append(`
      <optgroup label="${optgroup}">
        <option value="${option}">${option}</option>
      </optgroup
    `);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="item-category">
  <span class="category-title">Kitchen</span>
  <div class="actual-item">Spoon</div>
  <div class="actual-item">Knife</div>
  <div class="actual-item">Fork</div>
</div>

<div class="item-category">
  <span class="category-title">Living room</span>
  <div class="actual-item">Sofa</div>
</div>

<div class="item-category">
  <span class="category-title">Kitchen</span>
  <div class="actual-item">Plate</div>
</div>

<label for="item-select">Choose an item:</label>
<select id="item-select" class="item-select-field"></select>
thursday_dan
  • 553
  • 6
  • 17
0

hard way

const zip = (...arr) => {
   const zipped = [];
   arr.forEach((element, ind) => {
      element.forEach((el, index) => {
         if(!zipped[index]){
            zipped[index] = [];
         };
         if(!zipped[index][ind]){
            zipped[index][ind] = [];
         }
         zipped[index][ind] = el || '';
      })
   });
   return zipped;
};

const combined = zip($('.actual-item').toArray(), $('.item-category').toArray())

$(combined).each(function(){
  console.log({'value': $(this[0]).text(), 'category': $(this[1]).text()})
})
{value: "Spoon", category: "Kitchen"}
{value: "Sofa", category: "Living room"}
{value: "Plate", category: "Kitchen"}

PS thanks to this info

rzlvmp
  • 7,512
  • 5
  • 16
  • 45