Liquid. Looping through an array with an if condition then want to store the output of that in another array - shopify

{% assign leg = {{Predept.legs}} %}
{% for legs in {{leg}} %}
{% if {{leg[forloop.index0].direction}} == 'R' %}
{{leg[forloop.index0].arr_station_name}}
{%endif %}
{%endfor %}
I want to put the output of this for loop into another array. Any ideas?

Welcome, Jeet!
First, you don't ever nest the Liquid tags. Your basic loop should look something like this:
{% assign legs = Predept.legs %}
{% for leg in legs %}
<!-- Cool code & stuff here! -->
{% endfor %}
Now, in Liquid you can only create a new array by using the split filter on a string. We can also create a string by wrapping other commands with the capture tag. Putting that together, we get something like:
{% capture leg_data %}
{% assign legs = Predept.legs %}
{% for leg in legs %}
{% if leg.direction == 'R' %}
{% comment %}Output delimiter if needed {% endcomment %}
{% unless found_one %},{% endunless %}
{% assign found_one = true %}
{{ leg.arr_station_name }}
{% endif %}
{% endfor %}
{% endcapture %}
{% assign leg_data = leg_data | split: ',' %}
That will give us an array of all of our arr_station_name for the desired legs, but you may note that capture is also capturing all of the whitespace in there as well. If we need to prevent that from getting into our nice little array, we can use the whitespace-stripping - character on our tags to control that, giving:
{%- capture leg_data -%}
{%- assign legs = Predept.legs -%}
{%- for leg in legs -%}
{%- if leg.direction == 'R' -%}
{%- comment -%}Output delimiter if needed {%- endcomment -%}
{%- unless found_one -%},{%- endunless -%}
{%- assign found_one = true -%}
{{- leg.arr_station_name -}}
{%- endif -%}
{%- endfor -%}
{%- endcapture -%}
{%- assign leg_data = leg_data | split: ',' -%}
Hope this helps!

Related

Jinja DBT for loop union with some different columns across tables

I'm creating a master events table, where almost all of the same columns are in every table, but a few tables are missing one or two columns. In those cases I'd like to replace those columns with null whenever the column doesn't exist in the table. When I run the code below, every cell in the output table is NULL.
Assume columns 1 and 2 are in every table, but column 3 is in table 1 and 2 but not 3.
{{ config(schema='MYSCHEMA', materialized='table') }}
{% set tables = ['table1', 'table2', 'table3'] %}
{% set possible_columns = ['col1', 'col2', 'col3'] %}
{% for table in tables %}
{%- set table_columns = adapter.get_columns_in_relation( ref(table) ) -%}
select
{% for pc in possible_columns %}
{% if not loop.last -%}
{% if pc in table_columns %}
{{ pc }},
{% else %}
null as {{ pc }},
{%- endif %}
{% else %}
{% if pc in table_columns %}
{{ pc }}
{% else %}
null as {{ pc }}
{%- endif %}
{% endif %}
{%- endfor %}
from
{{ ref(table) }}
{% if not loop.last -%}
union all
{%- endif %}
{% endfor %}
I'd recommend using dbt_utils.union_relations for this. It does exactly what you describe -- it creates a superset of columns from all the tables and fills in nulls where appropriate.
{{ dbt_utils.union_relations(
relations=[
ref('table1'),
ref('table2'),
ref('table3'),
],
include = ['col1', 'col2', 'col3']
) }}
BUT, if you want to roll your own...
The problem with your code is this line:
{% if pc in table_columns %}
adapter.get_columns_in_relation returns a list of Column objects, not a list of strings. To compare pc to the name of a column, you could use:
{% set cols = [] %}
{% for col in table_columns %}
{% do cols.append(col.name) %}
{% endfor %}
...
{% if pc in cols %}
You can also remove a bunch of redundant code by pushing down the if not loop.last block to just the comma, so this all becomes:
{% for table in tables %}
{%- set table_columns = adapter.get_columns_in_relation( ref(table) ) -%}
{% set cols = [] %}
{% for col in table_columns %}
{% do cols.append(col.name) %}
{% endfor %}
select
{% for pc in possible_columns %}
{% if pc in cols %}
{{ pc -}}
{% else %}
null as {{ pc -}}
{%- endif %}{%- if not loop.last -%},{% endif %}
{%- endfor %}
...

Go through all available variants in Shopify liquid

I am trying to show all the available sizes from a product in the collection page.
I managed to write this snippet that will show available sizes, but only for one of the color combinations.
{% for option in product.options_with_values %}
{% assign downcased_option = option.name | downcase %}
{% if downcased_option contains 'size' %}
{% assign is_size = true %}
{% for value in option.values %}
{% assign variant_available = true %}
{% if product.options.size >= 1 %}
{% unless product.variants[forloop.index0].available %}
{% assign variant_available = false %}
{% endunless %}
{% endif %}
<span class="{% unless variant_available %}soldout{% endunless %}">{{ value | escape }}</span>
{% endfor %}
{% endif %}
{% endfor %}
But, let's say we have the next variants:
Green/32, Green/34
Blue/34
Black/34, Black/36
With the snippet above, it will not show available size 36 from black color as it's not available in green.
What I want is to go through every single size and show if availability, no matter the color.
Does someone know how to achieve this?
Thanks
Forgive me if I'm missing something but making the assumption that all variants have a size and there are only two options you just need to loop through the available variants and just display the variant name split it and display first or last where ever the size is in the options list. if there are loads of duplicates then put them in an array and run 'uniq'.
{% for variant in product.variants %}
{% if variant.available %}
{% assign sizesList = variant.title | split: '/' | first | append: ', ' }}
{% endif %}
{% endfor %}
{% assign sizes = sizesList | split: ', ' %}
{{ sizes | uniq | join: ", " }}

Build collection from tag array in shopify

I'm aware you can't filter collections via "OR" condition, but is there a way to pass an array of tags you want to build a collection out of? I'd like to build a giftfinder that allows the customer to select multiple options and it would show products that match ANY those tags - not products that contain ALL those tags.
I've tried doing this on an all products collection, but it only limits the results on the page you're currently on and it still seems to paginate for all the products in the collection
{% assign tagcategories = "Animals, Sloths" | split: ',' %}
{%- for product in collection.products -%}
{% for tagcat in tagcategories %}
{%- for tag in product.tags -%}
{% if tag == tagcat %}
{% include 'collection-product' with collection.handle %}
{% endif %}
{%- endfor -%}
{%- endfor -%}
{%- endfor -%}
Are there any other methods or workarounds to do what I'm trying to achieve? Thanks!
The best approach when it comes to product by tag is to use the default collection/handle/tag and request is via AJAX.
If you create a custom template only for the ajax logic so that it doesn't including the header and footer it will be easier on you.
The custom template will be something like so collection.ajax.liquid:
{% layout none %}
{%- for product in collection.products -%}
{% include 'collection-product' with collection.handle %}
{%- endfor -%}
So in your case you will have something like so.
(async () => {
const handels = ['animals', 'sloths'];
for (let index = 0; index < handels.length; index++) {
const handle = handels[index];
const response = await fetch(`/collections/all/${handle}`).then(res => res.text());
// do something with the response
}
})
If you still wanted to use just liquid you can wrap your current code with a paginate tag:
{% paginate colection.products by 99999 %}
{% assign tagcategories = "Animals, Sloths" | split: ',' %}
{%- for product in collection.products -%}
{% for tagcat in tagcategories %}
{%- for tag in product.tags -%}
{% if tag == tagcat %}
{% include 'collection-product' with collection.handle %}
{% endif %}
{%- endfor -%}
{%- endfor -%}
{%- endfor -%}
{% endpaginate %}
Please note that the liquid way will increase the load speed of the site depending on how many products you have!

How to add second product to cart in Shopify from product page

I'm using Shopify and am trying to add the options to add gift wrap and a carry case to products being bought.
I can use the item.properties to ask the user for the choice and show that in the cart.
I now want to add an additional product to the cart if item.properties is set to "gift wrap" or "carry case".
This code is placed in the product-template.liquid but does not work:
{% for property in item.properties %}
{% if property.last == "Gift Wrap" %}
<p>This would add gift wrap.</p>
<script>
jQuery.post('/cart/update.js', {
updates: {
32005672697928: 1
}
});
</script>
{% endif %}
{% if property.last == "Carry Strap" %}
<p>This would add carry strap.</p>
{% endif %}
{% endfor %}
{% endunless %}
Doesn't seem the code you have was intended to be used on the product page. It looks like it should be placed on the cart page within the {% for item in cart.items %} ... {% endfor %} loop.
Also, this code will add only 1 wrap product, even if customers add 2+ wrapped items. I would change the code to something like the below:
{%- assign numWrappedItems = 0 -%}
{%- for item in cart.items -%}
{%- for property in item.properties -%}
{%- if property.last == "Gift Wrap" -%}
{%- assign numWrappedItems = numWrappedItems | plus: item.quantity -%}
{%- break -%}
{%- endif -%}
{%- endfor -%}
...
{%- endfor -%}
{%- if numWrappedItems > 0 -%}
<script>
jQuery.post('/cart/update.js', {
updates: {
32005672697928: {{ numWrappedItems }}
}
});
</script>
I hope the above makes sense.

shopify pass a variable to settings

i want to do something like this in Shopify:
{% for i in (0..10) %}
{% capture slide %}slide{{i}}{% endcapture %}
{{ settings.slide }}//i need the value of this one
// i want to get the values for settings.slide1, settings.slide2 etc
{% endfor %}
Another example:
{% for i in (0..10) %}
{{ settings.slide[i] }}//i need the value of this one
{% endfor %}
This is a simplified version of what im trying to achieve.
Thanks
Try this:
{% for i in (0..10) %}
{% assign current_slide = 'slide' | append: i %}
{{ settings[current_slide] }}
{% endfor %}