Handlebars and async call

帅比萌擦擦* 提交于 2020-01-13 18:58:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!