问题
I use this helper to check wether an image exists or not:
Handlebars.registerHelper('checkLogo', function(url) {
UrlExists(url, function(status){
if(status === 200){
return new Handlebars.SafeString(url)
}
else if(status === 404){
console.log('no logo found');
}
});
});
function UrlExists(url, cb){
$.ajax({
url: url,
dataType: 'text',
type: 'GET',
complete: function(xhr){
if(typeof cb === 'function')
cb.apply(this, [xhr.status]);
}
});
}
I call it (with a url as arg) in my template like this:
<img src="{{checkLogo logo}}"/>
Im expecting {{checkLogo logo}}
to be replaced by the url but nothing gets returned. Is it maybe beacuse of the async action and because of this it has to be handled differently?
Thank you
回答1:
Though Handlebars doesn't support asynchronous helpers you can still use helpers to achieve this. Create some unique html with a helper and detect it being added to the DOM using MutationObserver. Then you can get a hold of the added img
element and modify it however you like.
A much simpler and more efficient solution would be to use the onerror
attribute of img
element to trigger some callback. Here's an example fiddle. Another fiddle that uses a handlebars template.
If you want to explore the Handlebars + MutationObserver way, I've created a helper that you can use or adapt. It's available at https://github.com/ekuusela/post-render-bars and demonstrated in this fiddle.
watch.js defines a function forHtml(html, callback)
which triggers a callback when the given html is encountered in the DOM. It modifies the html to temporarily have a class that makes it unique.
helpers.js defines the helper renderer
and the function createRenderer(getHtmlContentFn)
which wraps your function into a renderer and that can be passed in to a template and used as an argument for the helper.
回答2:
I wanted this as well, found a way:
Handlebars.registerHelper('myHelperFunctionName', function (item) {
var element_id = 'temp-prefix-' + item, item_html = false;
// make async call here:
SlowAsyncCallbackPromiseThing(item, function(item_object){
item_html = Handlebars.templates.item(item_object);
$('span#' + element_id).replaceWith(item_html);
});
if(item_html){//cache resolved immediately
return new Handlebars.SafeString(item_html);
}
// If the cache is barren, provide a loading span to be replaced later.
return new Handlebars.SafeString('<span id="' + element_id + '">Loading..</span>');
});
Now, when you load it, the inner jQuery simply replaces the temporary element when it eventually resolves.. not the best, but it's fast and works with Handlebars. I use a lot of localStorage caching, so some of the Promises resolve instantly. Absolute headache to troubleshoot till I figured out why it wasn't working always.
To adapt that to a property of an element.. wouldn't be that hard, but you'd need some way of identifying the element
来源:https://stackoverflow.com/questions/34905864/handlebars-and-async-call