Well why do we need to do this in CQ?
How is this usually done.
- A service
- An HTML template or even worse HTML embed in Javascript
- Some additional component specific Javascript
- cq:Component
What if there is an easy solution to create a component with AJAX using a Sling trick
- cq:Component
- Javascript library
/my-page/jcr:content/my-component.{selector}.html?{url-param}={param-value}
$.get("/my-page/jcr:content/my-component.{selector}.html?{url-param}={param-value}")
.success(function(data){
$("component-id").replaceWith($(data));
});
<c:set var="selectorArray" value="${'|'}${fn:join(slingRequest.selectors, '|')}${'|'}" />
<c:if test="${ fn:contains(selectorArray, '|testSelectorVal|') }">
//something rendered differently
</c:if>
<c:set var="paramValArray" value="${'|'}${fn:join(paramValues['testParam'], '|')}${'|'}" />
<c:if test="${ fn:contains(paramValArray, '|testParamVal|') }">
//something rendered differently
</c:if>
Avoid Hard Coding
We If we don't want to hard code our id, paths, selectors and parameters and we want to be able to put more than one of these components per page
I recommend using an unique identifiers, a data-attribute and a class.
<div id="${currentNode.identifier}" class="ajax-container"
data-ajax-path="${currentNode.path}">
</div>
We will create a Javascript module with the following function design as desired, this should be inside a cq:clientLibs folder.
window.AjaxComponent = (function(){
var module = {};
var buildFullPath = function(path,selectors,params){...};
module.executeCompentAjaxCall = function(id,path,selectors,params){
$.get(buildFullPath(path,selectors,params))
.done(function(data){
$(id).replaceWith($(data));
});
};
module.getSelectors = function(){...};
module.getParams = function(){...};
$(document).ready(function(){
$(".ajax-container").each(function(i,ajaxContainer){
module.executeCompentAjaxCall($(ajaxContainer).attr("id"),
$(ajaxContainer).attr("data-ajax-path"),
module.getSelectors(), module.getParams());
});
return module;
})();
Theses are just suggestions and you may development your Javascript library however you desire. This assumes your method of getting selectors and parameters are the same for every component and that you want your component requested on document ready.
If our AJAX request is called on document ready, I recommend hiding it via CSS first then showing the updated content or not rendering anything initially so we don't get a flickering effect. If the request is on user interaction a loading overlay is nice while the content is being requested.
In Conclusion
Requesting the entire component via Sling saves us a lot of work and is a very clean solution with less development effort. The main draw back is we are requesting slightly more data than using a JSON service.
If you plan on having dynamic content in one of your cq:Components use AJAX and this technique!