not sure how that can be done. The url comes from the data. So we pass it to the helper as a param. There is no click event. The page loads and displays the url and image (ideally).
you should be able to access through this.data
in the onRendered callback
sorry iām lost. So I move just the reactiveVar .set statement from the helper to onRendered? Or move the whole imageGrabber code to the onCreated and put only the .set in the helper?
In onRendered
you need to use var instance = this;
- itās the same scope as onCreated
.
so remove var instance = Template.instance();
from the helper
and add var instance = this;
to onRendered`
you removed the .set statement from the helper. We donāt need it anymore ?
onCreated - declare the reactiveVar
onRendered - handle the whole image grabber, you should be able to access the url from this.data
and note Robās context comment above, and set the value of the reactiveVar still inside the callback
helper - return the image to the template by getting the reactive var
also, I would have the list of urls in a parent template, and call the image grabber in an #each block per url
Maybe this:
Template.discover.helpers({
getImage: function() {
var instance = Template.instance();
return instance.imageResolverRequests.get();
}
});
Template.discover.onCreated(function() {
var instance = this;
var url = Helpers.addHttp(this.data.url);
instance.imageResolverRequests = new ReactiveVar();
resolver.resolve(url, function(result) {
if (result) {
instance.imageResolverRequests.set(result.image);
} else {
console.log("No image found");
}
});
});
Edited for missing ReactiveVar line.
so the instance var is not available in the helper so I changed it to Template.instance()
but seems iām not getting url
in the data in onRendered
here is what I got:
<template name="discover">
...
{{#each itemsInParcel this}}
<div class="panel-footer">
name: {{productName}} <br>
description: {{productDescription}} <br>
url: <a class="text-info" href="{{addHttp productUrl}}" target="_blank">{{productUrl}}</a> <br>
<img src="{{getImage productUrl}}" alt="">
price: {{priceJPY}}
</div>
{{/each}}
...
Template.discover.onCreated(function() {
this.imageResolver = new ReactiveVar();
});
var resolver = new ImageResolver();
resolver.register(new ImageResolver.FileExtension());
resolver.register(new ImageResolver.MimeType());
resolver.register(new ImageResolver.Opengraph());
resolver.register(new ImageResolver.Webpage());
Template.discover.onRendered(function() {
var instance = Template.instance();
console.log("page:" + this.url);
url = Helpers.addHttp(this.url);
resolver.resolve(url, function(result) {
if (result) {
instance.imageResolver.set(result.image);
}
});
//$(window).on("scroll", this.viewmodel.getScrollHandler());
var self = this;
this.autorun(function() {
self.viewmodel.loadingParcels(true);
self.subscribe('parcelsByDays', self.viewmodel.parcelLoadDays(), {
onReady: function() {
self.viewmodel.loadingParcels(false);
},
});
});
});
Template.discover.helpers({
getImage: function() {
// return the image into your template (when it gets updated)
return Template.instance().imageResolver.get();
},
onRendered console log is writing this
page:undefined
I thought onRendered fired once for the page. Will it fire for each url in the for each? or should i create a separate template for the each loop and more the grabber code to that templateās onRendered? Will try.
no luck. crazy. this is one of the hardest problems Iāve had in Meteor
Template.discover.onRendered(function() {
var instance = Template.instance();
in onRendered it is
instance = this
and this.url means url on this template instance
you probably want something like
Template.currentData().url
or address it somehow else, where you have that url ?
Thanks for all the help on this. 3AM now so Iām going to take a break. Must not be thinking clearly anymore at all.
Cheers!
So I just tested my code above and it works as expected. However, I used an async HTTP call to an external API rather than ImageResolver (which Iāve never used), but the principle is the same. Repo here.
Seems we were all over-thinking it. My CTO came in and solved it without any onRendered or onCreated code. Like this, in a single helper
var resolvedUrls = new ReactiveDict();
Template.discover.helpers({
getImage: function(itemUrl) {
itemUrl = Helpers.addHttp(itemUrl);
resolver.resolve(itemUrl, function(result) {
if (result) {
resolvedUrls.set(itemUrl, result.image);
}
})
return resolvedUrls.get(itemUrl);
},
});
I would perhaps add a check before the resolver though, so that you donāt resolve a url several times. A lot of things can trigger a rerun of a template helper.
var resolvedUrls = new ReactiveDict();
Template.discover.helpers({
getImage: function(itemUrl) {
itemUrl = Helpers.addHttp(itemUrl);
var resolvedImage = resolvedUrls.get(itemUrl);
if (resolvedImage) return resolvedImage;
resolver.resolve(itemUrl, function(result) {
if (result) {
resolvedUrls.set(itemUrl, result.image);
}
});
},
});
The var resolvedUrls = new ReactiveDict();
is a good idea in this case. However, this variable will be scoped to the file, and not to the instance. This could create issues in some cases where the dict actually contains instance specific state, and you have multiple instances of the template on your page.
I noticed that helpers are sometimes called before the template is ready. In cases that happened I was able to fix it by checking if the Template has actually rendered.
var instance = Template.instance();
if(instance.view.isRendered)
{
// action
}