How to check if a block is extended? - django-templates

To take an example of SO itself, the title can be set as
<title>{% block post_name %}{% block% } - StackOverflow</title>
However, if post_name is not defined, the title becomes - StackOverflow with the excess -
How can I test if a block is extended so that I can conditionally set the -

There isn't a way to make the parent template behave differently based on which blocks a child template defines. To get the desired output you'd have to remove the - from the parent template and add - at the end of the post_name block in each child template.
Alternatively, if you wanted to have the - StackOverflow suffix in some child templates but not others, you could move StackOverflow into the parent template's post_name block and then reference that text from within the child template using the {{ block.super }} variable.
In the parent template:
<title>{% block post_name %}StackOverflow{% block %}</title>
In the child template:
{% block post_name %}Title of post goes here - {{ block.super }}{% block %}

Related

How to pass a captured value (handle) from {% raw %} to get a object from shopify in liquid?

I'm using vue3 and liquid for some Shopify theme developments.In my case, there is a value from vue component and I want to use this value to get a shopify object within liquid file.
<div v-for="handle in featuredHandlesArray" :key="handle" >
{% capture article_liquid %}
{% raw %}{{ handle }}{% endraw %}
{% endcapture %}
{% assign article_obj = articles[article_liquid] %}
</div>
Here I'm getting above 'featuredHandlesArray' from vue component and looping with a v-for. There's no issue with it. If I echo these 'handle' value in the loop, it prints my relevant handle. Even when I echo captured 'article_liquid' variable below the '{% endcapture %}' tag, it prints too. But when I try to pass that handle to get the article object from shopify, it's nothing. It means 'articles[article_liquid]' is not working. I just want to get that article object from shopify by passing handle and assign that object into a variable like 'article_obj'.
If anyone experienced this kind of issue, please give me a support. Or any suggestion will be very appreciated. Thanks!

Shopify EventListener is not listening

{% javascript %}
window.addEventListener('resize', console.log('Screen size changed!'));
{% endjavascript %}
This code is supposed to run whenever screen resolution is changed but it only works once the page is loaded, it does not fire when I change resolution.
The reason this happens is because you are calling the function right away and therefore the console.log only outputs once the page is loaded.
What you would need to do is place this inside of a function like so:
{% javascript %}
window.addEventListener('resize', function() {
console.log('Screen size changed!')
});
{% endjavascript %}
That way, whenever the window is resized the function will run and the console.log will be output.
A further explanation on why this is happening can be found in this answer.

Vuejs - Slots rendering nonsensical properties

I am currently having issues passing raw HTML (entity form) to a slot for syntax highlighting.
Imagine having a slot like so;
<template v-slot:code-snippet>&lbrace;&lbrace; product.title &rbrace;&rbrace;</template>
Im receiving the error
[Vue warn]: Property or method 'product' is not defined on the instance but referenced during render
which is down to &lbrace;&lbrace; product.title &rbrace;&rbrace; - remove this and it works fine.
Is there anyway I can tell the instance to stop trying to render these "properties" as it is to be interpreted as plain text?
regards
As already noted you can use v-pre. I would say that is the correct answer but it is worth noting that there are other ways this can be done. Perhaps if other constraints exist these could be useful.
Hack 1:
Move the troublesome string to a data property:
<template v-slot:code-snippet>{{ code }}</template>
data () {
return {
code: '{{ product.title }}'
}
}
Hack 2:
Wrap everything in an interpolation and throw in a bit of JS string escaping:
<template v-slot:code-snippet>{{ '\u007b\u007b product.title \u007d\u007d' }}</template>
Depending on the circumstances this can also be adapted to work with v-text or v-html as appropriate.
For anyone else needing help simply wrap the content going into the slot with <div v-pre>;
<template v-slot:code-snippet><div v-pre>{{ $component->renderCode() }}</div></template>
The div doesn't seem to be passed through to the slot.

Vue.js interprets `<` and `>` in string literal as custom element

I have a simple Vue.js app, with this template:
<h1>{{ name || '<New Document>' }}</h1>
My goal is that if name is falsy, to use the text <New Document>. This is not intended to be a custom markup tag. I want Vue.js to insert this into the document:
<h1><New Document></h1>
Instead, I get this warning on the console:
[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
According to the documentation, using a pair of curly brackets, {{ and }}, means text interpolation, and the text value of that expression will be used. Instead, Vue.js seems to want to treat it as HTML.
Why is that happening? How can it be resolved?
This is a great question. Like you, I assumed that everything between the curly braces would be evaluated as an expression and injected into the template. That's what the documentation implies, and in all cases I've encountered this appears to be true... except when there could be an HTML tag in a string literal. At least, that's why my experiments seem to indicate.
Take the following example:
<h1>{{ name || '<span>hello</span>' }}</h1>
There are two ways the parser could read this:
An h1 tag containing curly braces - within those, an expression we need to evaluate later.
An h1 tag followed by the string {{ name || ', then a span, then another string ' }}.
In this case, the parser is built to choose (2), and this explains why you received a compile-time error. The parser indicated that you have a tag starting with <New Document>, but it didn't have a corresponding closing tag.
If this seems like an odd design choice, consider this code:
<h1>{{'<span>hello</span>'}}</h1>
What did the user intend here? Did he/she mean to surround a span with curly braces and quotes? Probably.
As for a solution, you could manually escape the string:
{{ name || '<New Document>' }}
Alternatively, you could solve this with a computed property, which will eschew the template parser altogether:
<template>
<h1>{{ nameOrNew }}</h1>
</template>
<script>
export default {
data() {
return {
name: false,
};
},
computed: {
nameOrNew() {
return this.name || '<New Document>';
},
},
};
</script>
Vue's template parser parses HTML first (split into tags and their content) and only then parses tags attributes and texts.
For your template it will be something like:
tag: <h1>
|
+- text: "{{ name || '"
|
+- tag: <New> (attributes: ["Document"])
|
+- text: "' }}"
You should think about template as a valid HTML first, with Vue's interpolations added later.
Documentation also states that:
All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers.
Ref: compiler/parser/html-parser.js
you can include all possible ignored elements in this config Vue.config.ignoredElements
Vue.config.ignoredElements = ['New Document'];
i hope it helps
The reason for the behaviour isn't clear to me, but here are two possibilities if you just need it to work:
<h1 v-if="name">{{ name }}</h1>
<h1 v-else><New Document></h1>
Or, as already pointed out in another answer:
<h1>{{ name || '<New Document>' }}</h1>

Vue - Added Nested Attributes Become Reactive But Why?

From the documentation (https://v2.vuejs.org/v2/guide/reactivity.html), I was under the impression that all attributes of an object need to be in the Vue data object to be reactive, unless they're explicitly added using Vue.set(object, key, value), or this.$set(object, key, value).
However, I'm using Rails with Vue and any data attribute I collect in a form, whether it's initially in the data object or not, becomes reactive. I'm using Jbuiler to build JSON objects, but I don't think that's affecting the reactivity, since if I remove the attributes there, they're still reactive when collected in the form. I've tried attributes that are on the object in Rails and ones that aren't, in Jbuilder or not, added via the console or not. All become reactive. This is great, but not the behavior I expect, so I 'd like to understand it.
Here's an example...
# Product attributes: name, code (note: not 'location'!)
# Rails Controller
def new
#product = Product.new
end
# JS
var product = gon.product // using Gon gem to pass variables
var app = new Vue({
el: element,
data: function() {
return {
id: id,
product: product
}
}
)}
# HTML
<div class="col-sm-3">
<input type="text" v-model="product.code" class="form-control form-control-sm" />
</div>
<div class="col-sm-3">
<input type="text" v-model="product.location" class="form-control form-control-sm" />
</div>
<div>
Product Code: {{ product.code }}
Product Location: {{ product.location }}
</div>
When I start typing in the product.location field, the output immediately appears on the screen, so it appears to be reactive. Examining the object in the console reveals a reactive getter and reactive setter for the product.location. The attribute isn't initially in the Vue console devtool but it appears as soon as I start typing in the field.
So, what gives?
From the documentation link above:
When you pass a plain JavaScript object to a Vue instance as its data option, Vue will walk through all of its properties and convert them to getter/setters using Object.defineProperty.
In other words, everything defined on component instance is reactive. This allows watcher instance to update all dependent values and virtual DOM.
$set method is used to ensure that reactivity works for deeply nested objects/arrays or previously not defined properties.
In addition, v-model directive uses $set method to update values, so even if value did not have getters and setter initially, those will be added after value has been updated.