We are developing an app which will display a button on product details page to perform some actions. We are using product.metaifields for displaying the same based on a condition. So basically the button display toggles depending upon the metafield value.
The issue we are facing is, activate the feature from admin section and then the button will not show up on the user side unless we do a hard refresh on the browser. What happens here is Shopify caches the metafield value so the condition checking will not work.
Is there any way to remove the page caching while we perform some action on the app?
When you render a page in Shopify, it renders everything including the metafield resource values you may access while rendering. There is no special caching of a metafield value. If you render a metafield "AAA" on a client-facing page, change the metafield using an App or the Admin to be "BBB" there is no signal to the already rendered page to redraw anything.
If you want dynamic behaviour, like rendering a button with a value based on a metafield resource, you will have to either do a callback to an App, get the new contents, and update the DOM, or use a push strategy like WSS:// to keep a channel open to a backend that monitors these things.
So to sum up, your problem is not one of cached data, but instead the fact that you're rendering a non-dynamic value, and expecting your UX to be dynamic.
Related
Which ways are possible to edit the live preview of the product page in Shopify with Inputboxes next to it?
Let's say the product is a poster, and i want to add a custom text on it.
When typing into the inputbox the text changes in real time on the product.
Can this be implemented in the shopify code with the basic version of shopify?
Or does this necessarily needs an app?
ADDITIONALLY:
Let me go a bit deeper. I have a code that can generate a QR code.
Now i want that the QR code to be previewed in the product. Now position and color of the QR code is different from any product. Would that need an app?
Yes you can to an extent.
First the ground rules:
You can't modify the product from the front-end and update the content or media in the back-end - this would be a huge security hole
The changes applied to the product will be visible only to the user who changed them
The solution is to use Javascript and update the content of the front-end. If you like to store the changes for that specific user you can save them as cookie or localstorage.
If you like to share this change to other people you will need to add a custom parameter in the URL of the page and generate the content from it and share that url.
Each one of these steps will require some custom Javascript that will affect only the user in question, if you like to modify the product in the back-end directly you will need some kind of an app for this.
On my mind it can be done if the dynamic text is applied over product image.
Detailed code would be too long to write here but here are the steps:
Add an input to your product form to add a custom property (https://community.shopify.com/c/Shopify-Design/Product-pages-Get-customization-information-for-products/td-p/616503)
Write a Javascript function to get input value in real time
Use this value to display it in a div in product image container
Position this div in CSS as absolute and style it as you wish
While image container position should be set as relative in CSS
HTH
I'm working on a Vue project, where I have a navbar component. On mobile, this component shows a title for the page. I need to set this title on a page by page basis, but haven't been able to find a reliable way to do it.
I've seen examples suggesting adding meta: { title: 'My Page' } to each of the routes for the app, then checking the matched route and applying the title. This doesn't work for me as on some pages the title will rely on data fetched from displayed page (e.g. /posts/:id would want the title to be the title of the post, which isn't available to the router).
Another option I considered is emitting an event, which sets the title. This would work, but would have to be reflected up multiple levels, and would require every page to have a title otherwise the previous title would remain after navigation.
Similar to the above, it could be implemented via Vuex to avoid having to pass the event up the chain, but would have the same issue of the previous title remaining after navigation. I could of course clear the value on route change, but this could introduce a race condition as the API request is cached, so revisiting a cached page could result in no title.
Ideally I want a mix between using meta values, and values dependent on the result of the API call. What is the best way to achieve this?
Wondering the best way to prevent a GTM tag from firing. I found https://rbardini.com/automating-gtm-data-layer-tests/ which tags about fetching the dataLayer variable and comparing it in an assertion, but this looks like a clumsy approach when you want to write to the dataLayer on every page.
For example, it suggests:
const getDataLayer = ClientFunction(() => window.dataLayer)
We use Google Tag Manager to automatically load tags on our website. Unfortunately one of them is CloudIQ (from PayPal) which pops up an iframe overlay offering a newsletter signup or ability to save your shopping basket. The Trigger in our GTM setup for that tag is simply 'All Pages'. When it pops up it generally blocks our test because Selectors cannot be clicked.
Our page flow is over several pages of an online shop, e.g.:
visit home page, click a product - navigates to a product page
click some options on the product page, then add to cart
go through checkout flow
So there might be many pages visited due to click actions.
There is an ability in GTM to define Variables and then use them in Exceptions for a tag, so I could prevent the CloudIQ tag firing either via a/ a global variable or b/ a dataLayer variable. However, I can't see how to elegantly get these set for each page visited during my test, such that they would exist when the GTM examines variables in order to block a Tag from being loaded. Fixture.beforeEach isn't right because it would only run once per fixture, and any data it set on the page's scope would be lost as soon as a page navigation occurs.
Anyone got experience of this sort of thing?
(The alternative of course is to detect the overlay, use switchToIframe to switch into the CloudIQ iframe and close it manually, but it pops up quite erratically and I'd prefer to simply disable the Tag altogether during tests as it's not core functionality of our website that we need to test.)
One way would be to set a custom user agent string to your test suite, create a custom javascript variable that returns the value for navigator.useragent, and make an exception trigger that blocks the tag.
Or any variation on that theme - set a cookie, use a url parameter, or if you test suite allow inject a global js variable, and check for the value in an exception trigger.
There is no need to avoid firing of events on the client side. Just mock the service routes for Google Tag Manager and CloudIQ and imitate correct responses for them.
Is there a way by which I can duplicate or clone dijit widgets?
Basically, idea is to improve page rendering performance by minimizing widget creation time.
We have a single page web application and we do not reload the entire page whenever the user performs any action.
The flow of events is as follows,
The main page is loaded by the browser. It contains a dijit ContentPane which acts as a master container and displays the entire page using various other dijit widgets like textboxes, tabs, datefield, Enhanced grid etc.
The user performs an action (e.g. click on a dijit button)
The application sends an ajax call to server which processes the button click event and generates UI of the next page.
Browser receives successful response from ajax call and calls refresh method of dijit ContentPane. Which triggers destruction of existing widgets and new set of widgets are created and placed at appropriate position. (instead of refreshing the entire page)
The user again performs some action and again the refresh method is called which triggers destruction of existing widgets and new set of widgets are created and placed at appropriate position.
Because of such architecture the browser has to destroy existing widgets and recreate them again and again. Which results in slow performance.
The idea is to have a set of widgets always readily available on the browser clone them and place at appropriate position and update them instead of recreating each time.
Yes this is possible with something called _AttachMixin.
Basically there is no getting around the fact that your widgets would need to attach event listeners to the HTML Document. What can be cut out though is the time in the Dijit Widget's lifecycle to generate the DOM. As we well know, simple Dijit widgets like a dijit/form/Button has a div inside a div inside a div etc.
This is explained in detail here http://dojotoolkit.org/reference-guide/1.9/dijit/_AttachMixin.html
Here is an example using Node.JS as a backend. http://jamesthom.as/blog/2013/01/15/server-side-dijit
This is a tough problem and this concept isn't explained very thoroughly. If you have a backend that is not Node.JS you have to manually make the widget string and pass it as a response to your AJAX and an follow the example from the 1st link (Ref Doc)
We have had lots of widgets of our app render nicely within the client side. A far less complicated approach would be to simply show / hide (instead of render and destroy) widgets as and when they are needed. I assume that you app's access policy would focus on data and not which person has access to which widget.
I want to enable caching for a page that loads when an ListView item is clicked. So when the user clicks a second time on the same item, the app will navigate to the previous cached page.
(I'm using LayoutAwarePages and I suspect that this should be possible if in the OnNavigatedTo method the NavigationMode parameter is different from NavigationMode.New)
Any ideas?
You affect the page caching by setting the NavigationCacheMode property of the page in its constructor. By default it is disabled, but if you enable it, you'll get the existing page instance every time you navigate to it. This means that even if the user navigates to a different item in your ListView, the same instance of the page will be reused.
I've found a library reimplementing the navigation framework to make it more like the one in Windows Phone, i.e.:
When navigating back the cached page is used.
When navigating forward a new instance of the page is created.
If I understand your question correctly, you require a different caching behavior from both of the above. To achieve that you could either base your alternative navigation framework on the one in the library I linked to or simulate the behavior by persisting just the page state for each item instead of actually caching the pages.