HTML If class paragraph contains string do - html

I am trying to edit code using Shopify and their Liquid templates. It should be simple and I've searched their site and online. Their suggestions have not provided me a solution.
This is the original line of code:
{% if settings.display_quickview_vendor %}
<p class="product-vendor"><label>Vendor</label><span></span></p>
{% endif %}
This statement will always be true, referencing the json file. Using the class="product-vendor" and the .js file, it inserts the vendor name with the Vendor label from product setup.
My goal is that when my vendor name is set to "--" (using a drop down in product setup) the vendor line of code will not be executed.
I've tried this
{% if settings.display_quickview_vendor %}
{% if product-vendor != "--" %}
<p class="product-vendor"><label>Vendor</label><span></span></p>
{% endif %}
{% endif %}
I've also replace the second if statement with the following.
{% if product.vendor != "--" %}
{% if product.vendor contains '--' %}
{% if product-vendor contains '--' %}
My experience is with C# and VBA. I have a feeling that I'm not fully understanding what it is that I need to be asking or searching for.
This is the .js file where the quickview window is called.
initQuickView: function() {
e(".quickview-button a").click(function() {
var i = e(this).attr("id");
return Shopify.getProduct(i, function(i) {
var a = e("#quickview-template").html();
e(".quick-view").html(a);
var o = e(".quick-view");
if (o.find(".product-title a").text(i.title), o.find(".product-title a").attr("href", i.url), o.find(".product-vendor span").length > 0 && o.find(".product-vendor span").text(i.vendor), o.find(".product-type span").length > 0 && o.find(".product-type span").text(i.type), o.find(".product-inventory span").length > 0) {
var n = i.variants[0].inventory_quantity;
o.find(".product-inventory span").text(n > 0 ? null != i.variants[0].inventory_management ? n + " in stock" : "Many in stock" : "Out of stock")
}
This is from the schema.json file.
{
"type": "checkbox",
"id": "display_quickview_vendor",
"label": "Display Vendor?",
"default": true
},
This is from the data.json file.
"display_quickview_vendor": true,

Related

loop through a for statement using an if/else with nunjucks and json

I'm trying to loop through a nested json file with nunjucks, give each object type a specific layout and sort all based on date.
So in my case I have two collections events and videos. Both collections will have an array of events and videos.
My file is named /content.json and structured as followed:
{
media: {
events: [
{
content_id: "1",
content_type: "event",
date: "01-11-2019",
etc: "etc"
},
{
content_id: "2",
content_type: "event",
date: "01-08-2019",
etc: "etc"
}
],
videos: [
{
content_id: "3",
content_type: "video",
date: "01-12-2019",
etc: "etc"
},
{
content_id: "4",
content_type: "video",
date: "01-09-2019",
etc: "etc"
}
]
}
}
I have tried to get the different object assigned with an if/else statement and then use a for loop to cycle through the array, but that has failed, see below:
{% for item in content.media %}
{% if item == events %}
{% for item in content.media.events %}
{% include "components/event.njk" %}
{% endfor %}
{% elif item == video %}
{% for item in content.media.videos %}
{% include "components/video.njk" %}
{% endfor %}
{% endif %}
{% endfor %}
I never got to try and sort all the content by date, but I have found:
{% for item in items|sort(attribute='date')%}
Can anyone guide me in right direction?
Thanks in advance.
AENM
This code outputs separated feeds by type of elements (event or video).
{% for event in content.media.events | sort(attribute = 'date') %}
{% include "components/event.njk" %}
{% endfor %}
{% for video in content.media.videos | sort(attribute = 'date') %}
{% include "components/video.njk" %}
{% endfor %}
If you need to output a mixed feed, you should join arrays to one and run trought it (fortunately each elements already have the type):
{% for item in [].concat(content.media.events, content.media.videos) | sort(attribute = 'date') %}
{% include "components/" + item.content_type + ".njk" %}
{% endfor %}
Aikon,
I got it now!!
It was another typo, you switched the media and events. (did you try to keep me sharp?! :-))
But that's why the concat didn't work!!
So this is the final working result:
{% for item in [].concat(media.content.events, media.content.videos) | sort(attribute = 'date') %}
{% include "components/" + item.type + ".njk" %}
{% endfor %}
Only the date is not in the correct order, but I think that has to with my grid setup.
Thanks for helping me out......

Pass an Array to an include to loop over

I have an include that can have >1 buttons depending on what is passed in.
Currently I have the following in the include:
{% if include.buttons %}
{% for button in include.buttons %}
<a class="{{ button.classes }}" href="{{ button.url }}">{{ button.title }}</a>
{% endfor %}
{% endif %}
Then I am trying to pass in the following data:
{% assign buttons = '[{ "title": "button 1", "url": "https://#", "classes": "btn btn-transparent" }, { "title": "button 2", "url": "https://#", "classes": "btn btn-primary" }]' %}
{% include header.html
buttons=buttons
%}
What I can't work out is how to pass the data correctly to the include so that I may loop through it.
The problem is the assignment of the data as a array. In liquid you can not directly initialize arrays. A workaround is to play with split.
However, using jekyll you can provide arrays via data files. Simply put your buttons in a file, say _data\buttons.yml with:
postXX:
- button1:
- title: "button 1"
- url: "https://#"
- classes: "btn btn-transparent"
- button2:
- title: "button 2"
- url: "https://#"
- classes: "btn btn-primary"
Now you could put a reference in the yaml-header of your post/page like:
---
your other yaml options....
buttons: postXX
---
Finally, assign the buttons and include them as you did in your code.
{% assign buttons = site.data.buttons[page.buttons] %}
{% include header.html
buttons=buttons
%}
With Liquid, you can't create an array with a literal expression like {% assign myArray = ["one","two","three"] %}.
You can only :
create empty one : {% assign emptyArray = "" | split: "" %}
create one from string : {% assign myArray = "one two three" | split: " " %}
You can then manipulate your array :
add an element to array : push or shift (jekyll specific filters)
remove an element from array : pop or unshift (jekyll specific filters)
merge two arrays with concat
and so on ...
So, your array can only come from a liquid array manipulation or some datas contained in configuration, data file or page front matter.

Using Twig or Grunt to create navigation from JSON array

I got some help generating JSON from folder structure via Grunt. That worked great.
Now, I want to take that JSON and create a menu based on the output.
Here is a sample of what I'm talking about.
{
"files": [
{
"name": "firstpage.twig",
"path": "folder1/subfolder1"
},
{
"name": "secondpage.twig",
"path": "folder1/subfolder1"
},
{
"name": "thirdpage.twig",
"path": "folder1/subfolder1"
},
{
"name": "fourthpage.twig",
"path": "folder1/subfolder1"
},
{
"name": "anotherpage.twig",
"path": "folder1/subfolder2"
},
{
"name": "yetanother.twig",
"path": "folder1/subfolder2"
},
{
"name": "heresanother.twig",
"path": "folder2/subfolder3"
},
{
"name": "anotherone.twig",
"path": "folder2/subfolder3"
}
]
}
I'd like to build a nav so that it would be like
<ul>
<li>
folder1
<ul>
<li>
subfolder1
<ul>
<li>firstpage</li>
<li>secondpage</li>
<li>thirdpage</li>
<li>fourthpage</li>
</ul>
subfolder2
<ul>
<li>anotherpage</li>
<li>yetanother</li>
</ul>
</li>
</ul>
</li>
<li>
folder2
<ul>
<li>
subfolder3
<ul>
<li>heresanother</li>
<li>anotherone</li>
</ul>
</li>
</ul>
</li>
</ul>
The sections of folder1, subfolder1, etc would be dynamically populated based off of going through the path entries within the JSON and parsing the unique ones out.
I am using a Grunt custom task to generate the JSON. I also am using Twig that gets rendered via a Twig Rendering Grunt package. There is no other framework to play with here, just pure Twig. It's all done through NPM.
I tried this so far but am obviously failing
{% for folder in files %}
{% set folders = folder.path|split('/') %}
{% for i in folders if i (doesn't already exist) %}
// Dynamic menu goes here
{% endfor %}
{% endfor %}
Just stuck here banging my head off the desk. :)
Thanks in advance for any help!
In the Gruntfile, the custom task that works is like this:
grunt.registerTask('twigList', 'Creates list of twig files', function() {
var obj = {};
obj.files = find('sections')
.filter(function(filePath) {
return filePath.match(/\.twig$/);
})
.map(function(filePath) {
let itemPath = path.dirname(filePath).replace('sections/','');
let pathSeparatorPos = itemPath.indexOf('/');
let rootPath = itemPath.substring(0, pathSeparatorPos);
return {
name: path.basename(filePath),
path: itemPath,
rootPath: rootPath,
}
});
grunt.file.write('data/page-list.json', JSON.stringify(obj, null, 2));
});
and then the quick and dirty twig is this
{% set _lastRootPath = false %}
{% for folder in files if folder.rootPath is not empty %}
{% if folder.rootPath != _lastRootPath %}
{% set _lastRootPath = folder.rootPath %}
{{ folder.rootPath }}
{% endif %}
{% endfor %}
{% set _lastRootPath = false %}
<ul>
{% for folder in files if folder.rootPath is not empty %}
{% if folder.rootPath != _lastRootPath %}
{% if _lastRootPath != false %}</ul></li>{% endif %}
{% set _lastRootPath = folder.rootPath %}
<li>{{ folder.rootPath }}<ul>
{% endif %}
{% if folder.rootPath == _lastRootPath %}
<li>{{ folder.name }}</li>
{% endif %}
{% endfor %}
It's not polished but it works

How to limit number of iterations when looping through object in nunjucks

I have a js object like this:
var data = [
{ src: "src1", name: "name 1" },
{ src: "src2", name: "name 2" },
{ src: "src3", name: "name 3" }
]
I am looping through it with Nunjucks:
{% for object in data %}
{{object.src}}
{% endfor %}
But I want to limit the number of iterations to 2.
How do I do that with Nunjucks?
I know there is a range option but I couldn't find how to use it in this case.
You could accomplish this a couple different ways:
A) Use loop.index0 special variable (Demo in Codepen)
Inside a for loop, you can use loop.index0 instead limit-var
{% for obj in data %}
{% if loop.index0 < 2 %}
{{obj.src}}: {{obj.name}}
{% endif %}
{% endfor %}
B) Add Custom Filter (Demo in Codepen)
But more readable is add custom filter limit and use it
var nunjucks = require('nunjucks');
var env = nunjucks.configure();
var data = [
{src: "src1", name: "name 1"},
{src: "src2", name: "name 2"},
{src: "src3", name: "name 3"}
];
env.addFilter('limit', function(arr, limit) {
return arr.slice(0, limit);
});
var res = nunjucks.renderString(`
{% for obj in data | limit(2) %}
{{obj.src}}: {{obj.name}}
{% endfor %}`,
{data}
);
console.log(res);
C) Use native slice() function (Demo in Codepen)
{% for obj in data.slice(0, 2) %}
{{obj.src}}: {{obj.name}}
{% endfor %}

Find object by id in an array of JSON objects with Twig

I am being passed an array that unfortunately I cannot restructure:
"options": [
{"name":"namea","text":"valuea"},
{"name":"nameb","text":"valueb"},
{"name":"namec","text":"valuec"},
{"name":"named","text":"valued"}
]
I need to be able to find the object with the name equal to namea, nameb, namec, etc. and then produce the appropriate text. I tried the following and few other variations of that but could not get it to work:
{% for item in event.options %}
{% if item.name == "nameb" %}
{{ item.text|capitalize }}
{% endif %}
{% endfor %}
Thanks in advance for any help.
Edit: I basically only have access to a text box to input HTML and Twig. I do not have access to framework, custom extensions, etc.
Edit: JSON with exact formatting:
{
"source": "TEST.COM",
"trigger": "test",
"options": [{
"name":"test_date",
"value":"31-05-2017"
},
{
"name":"test_number",
"value":"9081003"
},
{
"name":"test_test",
"value":"9asd003"
},
{
"name":"Name",
"value":"Todd"
},
{
"name":"test_other",
"value":"kslkjsfd"
},
{
"name":"test_help",
"value":"908sdf3"
}]
}
This is going to be very hacky either way (I feel the javascript way as mentioned in the comments would still be less hacky).
However as its multilined we could write a basic parser like thing (this is by no means bullet proof and fails if the content has a ", or the structure changes or whatever changes to be honest):
{# create an array of lines #}
{% set event = event|split('\n') %}
{# an array to hold our options #}
{% set options = [] %}
{# using a bool to track if we are inside the options part #}
{% set inOptions = false %}
{# this holds the name of the last name value we have passed #}
{% set currentKey = '' %}
{# go through each line #}
{% for line in event %}
{# if we are inside the options tag do our magic #}
{% if inOptions %}
{# check if the line starts with "name": and track the current key name #}
{# or check if it starts with "value": and set the current key to that value #}
{% if line matches '/"name":/' %}
{# split line on the double quotes and get the last bit #}
{% set currentKey = line|split('"') %}
{# cant get the array index piped in one go idk.. #}
{% set currentKey = currentKey[3] %}
{% elseif line matches '/"value":/i' %}
{% set currentValue = line|split('"') %}
{% set options = options|merge({(currentKey): currentValue[3]}) %}
{% elseif line matches '/\s*}]/' %}
{% set inOptions = false %}
{% endif %}
{% endif %}
{# check for the options sectioning start #}
{% if line matches '/^"options/' %}
{% set inOptions = true %}
{% endif %}
{% endfor %}
{{ dump(options) }}
This returns in my dump (which you didn't have so you cant see):
array:6 [▼
"test_date" => "31-05-2017"
"test_number" => "9081003"
"test_test" => "9asd003"
"Name" => "Todd"
"test_other" => "kslkjsfd"
"test_help" => "908sdf3"
]
As an actual array where you can then call options.test_date but all this is super hacky, it still can be improved but twig is not made for it and the syntax gets so clunky its hard to maintain.