2

I'm trying to write a custom filter display template. My template requires some external calls, and thus requires some async work.

How can I output my filters after the initial render?

I've duplicated the outputFilter method from the default template. Then I call it in a PostRender callback.

This does not works, probably because the context in no more present.

Any advice ?

To give a bit of background, I'm trying to create a custom refiner, that receive filters from the query results. These results are flat, but I want to rebuild a tree of filters (each values can have parent/child relationship).

Here's a simple repro template:

    // Fill the arrays with refinement values
for (var i = 0; i < listData.length; i++){
  var filter = listData[i];
  if(!$isNull(filter)){
    filter.RefinementTokens = [filter.RefinementToken];
    filter.RefinementTokenWrappedValues = [Srch.RefinementUtil.stringValueToEqualsToken(filter.RefinementValue)];

    EnsureScriptFunc("sp.js", false, function(){


            var context = SP.ClientContext.get_current();         

            // load some data

            context.executeQueryAsync(Function.createDelegate(this, function(){}
                outputFilter(filterData.Name, filter.RefinementCount, refiners, addMethod, "ms-displayBlock", true);

            ),Function.createDelegate(this, function(){}

            )); 



            });
        });
    });

  }
}     
2

Instead of displaying the values from the filter by default, you have to do it from within your PostRender function.

Best is to create an empty container with a unique class like this:

<!--#_
    var containerClass = ctx.ClientControl.get_nextUniqueId() + "_container";
_#-->
<div id='Container' class="_#= containerClass =#_">
</div>

In your PostRender function, you have to write your async calls like this in order to be able to know the variable when the call is completed:

AddPostRenderCallback(ctx, function() {
    (function(containerClass) {
        // Do your async calls

        // Insert the HTML on the page
        var elm = document.getElementsByClassName(containerClass);
        if (elm.length > 0) {
            elm[0].innerHTML = "YOUR-HTML-OUTPUT";
        }
    })(containerClass);
});

Be aware, you will not be able to make use of the outputFilter function. You will have to write your own HTML markup and append it to the DOM yourself.

An example of this approach can be found in one of these templates on GitHub: Retrieve the list name in a display template

  • Maybe I can combine AddPostRenderCallback and CoreRender, like you do in your article? This would allow me to keep using display template, controlling the content of the context? – Steve B Sep 24 '15 at 7:05
  • I would do everything within the same template and not use the CoreRender function. CoreRender solution is good when you use the CSWP or SRWP because you are loading different results. But in the refiner template you are loading everything. – Elio Struyf Sep 24 '15 at 7:52
  • 1
    sorry for the long delay. I've ended up with custom DOM generation as you suggested. Not as easy as html template engine, but functionnal. Your blog is a gold mine to decrypt how refiners js API work. As it's undocumented by microsoft, your work is very impressive. – Steve B Dec 14 '15 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.