Pass variables inside render to outside? - shopify

It seems impossible for the outside caller to use any variable inside a render? Take this for example:
test.liquid:
{% assign test_xyz = '123abc' %}
template.liquid:
{% render 'test' %}
{{ test_xyz }}
Which outputs nothing.
How can the outside use variables inside render? Can render return anything? Or is it not possible in Shopify any more since include has been deprecated?

How can the outside use variables inside render?
It can't. That would violate encapsulation. When a partial template is rendered, the code inside it can’t access its parent’s variables and its variables won’t be accessible by its parent. This encapsulation makes partials easier to understand and maintain.
Can render return anything?
Unfortunately not. But maybe we are doing a mistake by thinking about render tag as of a function (which doesn't exist). My guess is that Shopify is trying its best to simplify liquid as much as possible, thus making server side rendering faster.
Or is it not possible in Shopify any more since include has been deprecated?
include tag is deprecated already for around 3 years already and it still can be used as there are no plans for removing it (at least I could not find any announcement stating that). It definitely affects the publishing process though, if you'd like to sell your theme in market place. The best option is to rethink the theme structure I guess.

Related

Storing Global Variables In App - Find Instance of Class or use Singletons?

Sorry for the title not being very informative. I'm working on a Qt app which has a lot of subwindows and menu items flying around everywhere. I want to be able to read and write to global variables from all various objects that sit in the app, and it's tedious and breaks easily if every object needs to carry a reference to a single class. There must be a better way of doing this.
My first guess was to use singletons, but does anyone have better suggestions?
My Current solution is to have a module which I never instance, only import. This module contains functions and variables which do not sit in any particular class. Are there any pitfalls here that I'm not aware of?

Is is proper to use "this" when referencing variables in vuejs v-if expressions?

Many of the examples for v-if use unqualified variable names such as:
<h1 v-if="awesome">Vue is awesome!</h1>
but I am wondering of the following code is equivalent?
<h1 v-if="this.awesome">Vue is awesome!</h1>
It seems to work correctly but I'm seeking some guidance on pros/cons of doing this.
The reason I ask is because when specifying v-if, "this" is not recommended, but when developing computed properties, "this" is required to reference model variables.
This makes things inconsistent for developers.
From the vue.js source code, they are using the javascript "with" statement to evaluate v-if tags to eliminate the need for the "this" qualifier. However, use of "with" is generally discouraged here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
I personally don't want to use "this" on v-if but it'd be even nicer to not have to use it in computed properties as well.
Variables in Vue template Keys are actually keys that are evaluated against component instance. These two snippets are equivalent, so this can be omitted.
this is needed in Vue templates in case of dynamic keys, e.g. for this[this.awesome]:
<h1 v-if="this[awesome]">Vue is awesome!</h1>
This is rarely needed in practice because a cleaner way is to move awesome access into computed property or a method.

vue.js how to organize front-end data (e.g. product information)

What is the correct pattern to store e.g. static product information data within a vue2 single page application?
Previously I've used an external js file that included a JSON with product-attributed (e.g. name, weight, height etc).
I don't want to load via AJAX since the spa needs to work without a web-server.
While VueX is meant to provide to a single source of truth for dynamic data throughout your single page application, I think it's also the proper and clean way of storing static data. VueX allows you to write getters and setters (as mutations / actions), now if you simply leave those setters out of your module you'll have a centralized store module that is read-only but available in every component.
Why is that better than just using a static JSON file?
Using a JSON file will expose the entire content to every single component that uses that file. In some cases that might be what you want, but it's by far not as flexible as having multiple getters that allows you to define the exact scope of what each component should receive. Also VueX uses all observable patterns and best practices from Vue itself, so the integration of your data in for example computed properties is super easy. Due to the getters pattern you'll also be able to define any kind of filtering or sorting in one place that you can share in your entire application. While that might not be what you need right now, keep in mind your requirements may change over time and simply having the option to easily implement that later is also a good thing. Same goes for reading the data from an Endpoint instead of having it statically. Your application might not need that right now, but in case you want to do that somewhen in the future, vuex will make it super easy to transition to dynamic data without you having to change any component.
What speaks against VueX?
Not that much. While it's a little bit of overhead if you really only use it for static data, the possible scalability it offers you is worth that minor downside.

When to use method over computed property setter and vice versa?

When using Vue.js, when should you use a method or a computed property setter? There seems to be little distinction in the documentation, or numerous articles. Usually articles present computed property setters as little more than a footnote.
Given that both methods and setters accept parameters, is there a particular reason you'd use one or the other? As far as I can see methods would be all you need.
Edit:
This is literally not a repost because the linked SO answer contains the word setter once and only in vague passing:
computed properties are converted into a property of the Vue with a getter and sometimes a setter.
Great, so how does this elaborate on the subject of this post, when to use a SETTER vs a method?
Computed properties are cached so they can benefit you when it comes to performance. They do not work like methods, as they do not accept arguments.
I use them mostly to modify existing data or make it easier to access nested data.
The part about caching is something that can end up being a hassle. They will always cache unless their direct dependencies change. Properties within computed properties that are within controls blocks will usually not update the computed property(not seen as a direct dependency).
This is something you need to be aware of.
When using things like large v-for lists you will want to to take advantage of the caching ability of computed properties since unlike with a method you won't have to perform the logic inside of it over and over, unless the direct dependencies of the computed property change.
Computed properties should be used to display data relative to existing data. While methods should be used to do an action and/or change data.

When to use Seaside components, and when to use simple render objects?

I have been developing a web application in Seaside+Squeak recently, and have found it to be a wonderful experience. Seaside really is head and shoulders above every other framework out there, and I feel as though I am working at a higher level of abstraction (above the HTTP request/response cycle and HTML templating that other frameworks make you deal with).
That said, I'm a little confused about Seaside components. I recently had to display a list of objects on a component (similar to the stackoverflow front page). At first I made each object a component (a subclass of WAComponent), but this proved to be really wasteful, and I had to set #children dynamically in the parent component for it to work at all. I then tried making them render objects (objects that aren't subclasses of WAComponent, and render using renderOn: instead of renderContentOn:, like components do). This worked, but now they could no longer access global state in the session object as components can (using #session). Then I discovered "WACurrentSession value", which gives any object access to the current Seaside session object. I was now able to make them render objects. In addition, I discovered that I could rewrite a lot of my other, more minor components as render objects, too.
Besides needing call/answer or backtracking state, what other reasons are there for using components over render objects?
This is a frequent point of confusion for new Seaside users. We have tried hard to make this clearer in Seaside 2.9, which is currently in Alpha, but I will try to focus on 2.8 here since it sounds like that is what you are using.
First of all, you are correct that you do not need to use a Component in order to access the Session. Seaside 2.9 moves #session up to a new class WAObject which makes it accessible to almost all Seaside objects (including Components) but you can definitely refer to WACurrentSession yourself for now in 2.8.
Components provide roughly the following functionality in 2.8:
#renderContentOn: is called with an instance of whatever renderer class you specify in #rendererClass (instead of whatever renderer is in use when your object is asked to render itself)
A hook (#updateUrl:) to allow updating the URL used by the renderer to generate links
Hooks (#updateRoot:, #style, #script) to allow updating the HEAD section of the HTML document
The ability to be the root of an Application
Hooks (#updateStates:, #states) to make state backtracking easier
A hook (#initialRequest:) to allow initialization based on the request that caused the Session to be created
A facility (#children) to make sure all components below you will also have the above hooks called on them
The ability to add Decorations
The ability to show/answer/call (uses Decorations)
Some convenience methods (#inform:, #isolate:, etc)
If you don't need any of the above, you don't need a Component. If you need any of the above, you pretty much do need a Component unless you want to implement the equivalent functionality on your own class.
The simplest metric is probably: if you intend to keep the object around between HTTP requests it should be a Component; if you intend to throw the object away and create it on each rendering pass it probably doesn't need to be. If you imagine an application that was displaying blog pages, you'd probably have Components for a menu, a blog roll, the blog body, each comment, and so on. You might want to factor out the reading of the blog's markup and generation of its HTML so that you could support different markups or different renderers and so that the comment Components could support the same markup. This could be done with a non-Component class that implements #renderOn: and could be created and used by other Components as needed.
Seaside 2.9 currently splits up the above functionality by making WAPresenter concrete and introducing WAPainter as its superclass. 1-3 above are implemented on WAPainter and 4-7 on WAPresenter so you have your choice of what to subclass depending on your needs. It also removes a lot of methods from WAPresenter and WAComponent in an effort to make them easier for end users to understand.
Hope that helps.