Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
Locked
0

assign / variable in for loop argument

Engaged ,
Oct 07, 2015 Oct 07, 2015

So normally we might set a loop argument up like this:

{% for item in webapp1.items %}

But I want to set the argument (not sure if that's the right terminology) as a variable, so something like:

{% assign arg = 'items' %}

{% for item in webapp1.arg %}

...


or


{% assign arg = 'webapp1.items' %}

{% for item in arg %}

...


but this doesn't work (I'm assuming because the variable is treated as a string and not a true argument).


Is there any way to achieve the same idea?

Or some way to "convert" the variable into the right data type...?

TOPICS
Developer
3.9K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Beginner , Oct 07, 2015 Oct 07, 2015

I'm going to assume you want to do this within the large_product.html template - one way of doing this might be to approach it the following way:

{% for attr in this.attributes -%}   

  {% assign key = attr[0] -%}

  {% assign values = attr[1] -%}

 

  {% for value in values -%}

    {{ value.id | prepend: "ID: " }}

    {{ value.name | prepend: "Name: "}}

    {{ value.displayType | prepend: "Display Type: " }}

    {{ value.image | prepend: "Image: "}}

    {{ value.price | prepend: "Price: "}}

 

...
Translate
Community Beginner ,
Oct 07, 2015 Oct 07, 2015

The following should work - if you use quotation marks, or apostrophes it will assume it is a string - not an array like it is.


{% assign arg = webapp1.items -%}

{% for item in arg -%}

Also - I am just curious why do you want to put the items within their own variable? It seems like an unneccesary step in most situations to duplicate the work (especially if its a large amount of items).

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Oct 07, 2015 Oct 07, 2015

Thanks Justin.

Ok, so that works (and I see why), however I reduced my example to simplify the question and my use case goes a little deeper.

Consider that my 'end result' variable is that I'm using is constructed by other variables, so:

{% assign part1 = 'webapp1' %}

{% assign part2 = '.items' %}

{% assign arg = part1 | append: 'part2' %}

{% for item in arg %}

...


Resulting in the argument being a string because of how it is constructed:


{% for item in "webapp1.items" %}

...


How do I force it to be seen as an argument and not a string?

I've tried converting it to a number and boolean just to see, but that doesn't work either.


The reason for doing this is because the for loops are looping collections/items that are variable and the names of those collections are sourced from a dynamic array.

So I'm using the above for loop within another for loop which has the array of variable I want to use (don't worry, the loops are only small - 4 or 5 items generally).


Something like:


{% for a in array %}

    {% assign part1 = a.name %}

    {% assign part2 = '.items' %}

    {% assign arg = part1 | append: 'part2' %}

    {% for item in arg %}

...


I need a way to join the arguments, like as in javascript it might be:


{% for a in array %}

    {% for item in a + '.items' %}

...


but liquid doesn't work this way as far as I know.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Oct 07, 2015 Oct 07, 2015

Adam's after computed property keys. I did something similar recently:

    {% assign thisProduct = webapp.items[0] -%}
   
    {% for blockN in (1..9) -%}
        {% assign keyPrefix = "Block " | append: blockN -%}
        {% assign headingKey = keyPrefix | append: ": Heading" -%}
        {% assign contentKey = keyPrefix | append: ": Content" -%}
   
        <h1>{{ thisItem[headingKey] }}</h1>
        <div>{{ thisItem[contentKey] }}</div>
    {% endfor -%}

This goes through the custom fields of a webapp which are predictably named, like Block 1: Heading, Block 1: Content, Block 2: Heading etc etc.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Oct 07, 2015 Oct 07, 2015

Thanks Robert,

This looks very interesting... I'll try and wrap my head around this

I have another reply here to Justin's post giving more info on my issue, but it's being 'moderated' by the forum so it may be a while before it shows up... grrrr

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Oct 07, 2015 Oct 07, 2015

Oh. looks like it's been approved now

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 07, 2015 Oct 07, 2015

Hey Adam,

Thanks for the Elaboration - I don't think given Adobe's build of liquid that we currently have the ability to do that with any filters - Shopify's Liquid has a Filter called Handleize that would do exactly what you are saying - but unfortunately it doesn't work on BC (Some of Shopify's Liquid filters do work on BC that havent been documented yet).So I think you may be out of luck at least with this avenue - could you maybe elaborate on your ultimate goal (Why you are constructing these out of two strings?)

Hopefully we can see if we can find a solution together here.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Oct 07, 2015 Oct 07, 2015

Thanks Justin,

My goal is to rebuild the attributes listing of a ecommerce product entirely with liquid. But I'm struggling here because of how the JSON data is output from BC (each attribute is an object inside the 'attributes' object named by their custom attribute name, they are not arrays within the object, so this is stumping me).

Looking ahead into my goal, I also see an issue with knowing the attribute type (checkbox, dropdown, radio...) as we only get that info from within each option rather then at the object level.

Then..... I can see that each options HTML 'name' attribute (ie: name="", not the text name) is not available in liquid, so this might be an issue also (need to do more tests here).

So there will be some challenges ahead but I thought I'd start here with the first one

Why am I recreating the attributes? Just for the fun of it ...and also to ultimately get full control over how we can present product attributes.

Maybe I'm looking at it all from the wrong angle. Happy to be shown a different way if so. This is pushing my coding comfort level.

In saying that, the initial problem by itself I'd like to solve regardless of my end goal if possible, as I've come across wanting similar before (variables/strings as arguments).

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Oct 07, 2015 Oct 07, 2015

I'm going to assume you want to do this within the large_product.html template - one way of doing this might be to approach it the following way:

{% for attr in this.attributes -%}   

  {% assign key = attr[0] -%}

  {% assign values = attr[1] -%}

 

  {% for value in values -%}

    {{ value.id | prepend: "ID: " }}

    {{ value.name | prepend: "Name: "}}

    {{ value.displayType | prepend: "Display Type: " }}

    {{ value.image | prepend: "Image: "}}

    {{ value.price | prepend: "Price: "}}

  {% endfor -%}

{% endfor -%}

Essentially you could build the container (lets say you had a dropdown (you arent going to know until you get into the values of attribute - but Im going to assume you can only have one type of a value - So a Dropdown, Select or Radio List. on the last item of the array you can set the type based upon the DisplayType Variable... have a switch .. or even just check the first value of an attribute and set it before you loop through them... I would then have a switch that builds the appropriate "holder" such as <select> before and after the 2nd For loop - and within the 2nd for loop build the "options" using an item like <option> , also adding a Default "Please select an option" item...

You could really do this for a listing of products as well, this set of loops just needs to reside within a loop going through the products - hopefully this is helpful.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Oct 07, 2015 Oct 07, 2015

Awesome, that looks promising. Thank you!

It was the first key/value part that I wasn't up with, so I think that's making sense to me now...

And yes, your suggestion with looping first to check type and then looping to build the containers is where I was going to head too.

I have to check if not having the name attribute will be an issue though (I'm thinking it will be - with BC there's always one little simple bit that stuffs the whole thing!!!)

Thanks so much Justin and Robert for sticking with me and assisting. I'll post my findings here if I get it all working.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Oct 08, 2015 Oct 08, 2015

Just reading up on this for the first time.

1. Assign and things like module parameter passing do not support object data, If you find it does in some cases this is a lucky outcome but very likely also buggy. I have requested for these to support that as an idea on the developer forum.

2. The related product attribute output by default in liquid is a bit broken, this is something I also raised and BC have got back to. You will find important data for the scripting to work missing etc. You can not fully build the attributes output in liquid to be feature parity at this time so do not try. I have, BC been told, waiting for updates

3. You can do a bit more with module_data on product large layout, but again this actually has some missing data you need for the BC scripting to work. your other option is to have a full understanding of the script to server BC calls and completely rebuild the BC scripting BUT again, you got some missing data you need to complete it fully. (Again I tried that too)

Hope that helps.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Oct 08, 2015 Oct 08, 2015

Thanks Liam, all good to know.

1. Ok, understood.

2. I've so far only found one piece of critical info missing in the liquid data and that is the mandatory state - but I've found a fairly smooth workaround for this.

As for the BC scripts not being loaded for the attributes module, what I did here was still include the module on the page but just comment it out or hide it (HTML comments not liquid comments). That way BC still loads the scripts it normally would.

To combat duplicate IDs on the form fields I just made sure the module was below my custom form in the code and it seems the first encountered ID is honoured while following duplicates ignored (I'm assuming at this point all browsers behave the same in this regard... haven't tested cross browser yet)

So at the moment (early days though) I have a working model that I haven't been able to break yet.

I haven't touched inventory/product variation yet but I'm thinking that probably has nothing to do with the front-end so should hopefully still work fine if those options are turned on.

I'd be interested in sharing the code with you once I'm finished to run your eye over it to either validate it works or fine any holes if you're keen?

3. Understood. I haven't look down the module_data avenue yet but thinking perhaps it could be used in conjunction with my current solution to properly plug the gaps with the mandatory state and any inventory/variation issues encountered???

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Oct 08, 2015 Oct 08, 2015
LATEST

With 2 Adam you need to look at it more closely..

- How does BC know to associate attributes, how BC knows to attach to the product, how the pricing and SKU stuff works with attributes and associated product and so on. Your missing quite a bit (about 4/5 things) to make those work properly. Face value you may get an output for example, add to cart though - you wont see attributes come through etc. Look at it carefully - more them eats the eye and you will see what I mean.

This is experience, I know

Your doing something I did a year ago and the data is still not there.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines