AEM HTL looping using data-sly-repeat - aem

<footer id="footer">
<div class="container">
<div class="row double">
<div class="6u">
<div class="row collapse-at-2">
<div data-sly-repeat="${properties.colNum}" data-sly-unwrap>
<div class="6u">
<h3>Accumsan</h3>
<ul class="alt">
<li>Nascetur nunc varius</li>
<li>Vis faucibus sed tempor</li>
<li>Massa amet lobortis vel</li>
<li>Nascetur nunc varius</li>
</ul>
</div>
</div>
</div>
</div>
<div class="6u">
<h2>Aliquam Interdum</h2>
<p>Blandit nunc tempor lobortis nunc non. Mi accumsan. Justo aliquet massa adipiscing cubilia eu accumsan id. Arcu accumsan faucibus vis ultricies adipiscing ornare ut. Mi accumsan justo aliquet.</p>
<ul class="icons">
<li><span class="label">Twitter</span></li>
<li><span class="label">Facebook</span></li>
<li><span class="label">Instagram</span></li>
<li><span class="label">LinkedIn</span></li>
<li><span class="label">Pinterest</span></li>
</ul>
</div>
</div>
<ul class="copyright">
<li>© Untitled. All rights reserved.</li>
</ul>
</div>
</footer>
I am trying to use data-sly-repeat to loop and I have verified that the value of colNum is 2 but still the loop is running only once. In other words, it doesn't loop through irrespective of the value. I also hardcoded the value 3 but it still won't run the loop more than once. Not sure what I am doing wrong here.
Thanks in advance

In sightly you can only iterate over a collection using sly-repeat or sly-list.So instead here instead using the ColNum directly you will have to make a simple collection .
Refer: https://docs.adobe.com/docs/en/htl/docs/block-statements.html

It seems you have misunderstood how data-sly-repeat is intended to be used. You can read their documentation to get clarification.
Two things:
data-sly-repeat repeats the whole element that is marked, while data-sly-list only repeats the content of the element. In your case it seems list is more appropriate.. You can eliminate the actual div that you are currently unwrapping.
Rather than passing in a number of times to repeat the HTML you pass in a list of things to iterate over. The html is rendered for each item in the list, with the ${item} variable being used to hold the current item.
So, you'll have to write some Java of JS code to turn your colNum into a list of that size.
For example, using the JS Use API. (see this question for ways to create empty iterable arrays)
"use strict";
use(function () {
let n = properties.get("colNum", 0);
return {
columns: [...Array(100)] // empty, iterable, array of size n
};
});
And calling it from the HTL. Notice I removed the extraneous div and am using data-sly-list to loop over the n length array of empty elements
<div class="row collapse-at-2"
data-sly-use.config="<JS-file-name>"
data-sly-list="${config.columns}">
<div class="6u">
<h3>Accumsan</h3>
<ul class="alt">
<li>Nascetur nunc varius</li>
<li>Vis faucibus sed tempor</li>
<li>Massa amet lobortis vel</li>
<li>Nascetur nunc varius</li>
</ul>
</div>
</div>

data-sly-repeat needs an iterable object. You can provide a dummy array with the needed number of elements or, even better, an array with usefull things, such as column names or data.

Related

How to recursively search the DOM and return first element that has a specified class

For example - return the 1st element that has class = "title".
The result in this case should be div3.1
Should only use vanilla JS.
<body>
<div class="container">
<div class="abc"> div1</div>
<div class="abc"> div2
<div class="abc">div2.1
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, ipsum?</p>
</div>
<div class="abc">div2.2</div>
<div class="abc">div2.3</div>
</div>
<div class="abc"> div3
<div class="title">div3.1</div>
<div class="title">div3.2
<img src="" alt="">
</div>
</div>
</body>
I don't know about recursively, but querySelector() does just that. It will find the first element that matches the given parameter. The parameter is a CSS selector, so:
id: #abc
class: .abc
attribute: [abc]
tag: div
There's the old school way as well using getElementsByClassName():
var abc = document.getElementsByClassName('abc')[0];
The getElementsByClassName() returns a HTMLCollection/NodeList of all elements with a given className, using the bracket notation ([0]) suffix insures that it only returns the first element of the NodeList.
Demo
var title1 = document.querySelector('.title');
var title2 = document.getElementsByClassName('title')[0];
console.log(title1.textContent);
console.log(title2.textContent);
<body>
<div class="container">
<div class="abc"> div1</div>
<div class="abc"> div2
<div class="abc">div2.1
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, ipsum?</p>
</div>
<div class="abc">div2.2</div>
<div class="abc">div2.3</div>
</div>
<div class="abc"> div3
<div class="title">div3.1</div>
<div class="title">div3.2
<img src="" alt="">
</div>
</div>
</div>
</body>
I'm afraid you provided too little details in your question. If you want to find element with specified class, you can use document.querySelector method.
You can't "recursively" search whole DOM (starting from certain node I'm assuming?), but you can search specific DOM "branch" (element and its parents, up to document body). You can use function like:
function findElementWithClass(sourceElement, className){
var element = sourceElement; //selected DOM node
while(element !== document.body){
if(element.classList.contains(className)){
break;
}
element = element.parentNode;
}
return element;
}
After while loop you can make additional check if element you wanted has been found - if not, you can return false or do whatever you like.
JS Fiddle link: https://jsfiddle.net/8o9jzt8h/

How auto active Getuikit accordion

I want solve my problem with Getuikit.
Accordion plugin is working. But I want make active (clicked) specific accordion on page load.
How can I do this ?
edit: getuikit v2
<div class="uk-accordion" data-uk-accordion="{collapse: false}">
<h3 class="uk-accordion-title">Accordion 1</h3>
<div class="uk-accordion-content">
<!-- Content -->
</div>
<h3 class="uk-accordion-title">Accordion 2</h3>
<div class="uk-accordion-content">
<!-- Content -->
</div>
<h3 class="uk-accordion-title">Accordion 3</h3>
<div class="uk-accordion-content">
<!-- Content -->
</div>
<h3 class="uk-accordion-title">Accordion 4</h3>
<div class="uk-accordion-content">
<!-- Content -->
</div>
</div>
Example: How make "Accordion 3 & Accordion 4" active ?
I've found the answer on SO. Here someone opens all accordions on page, so I've tweaked the code little bit for you. You can choose, which accordion you want to open on init.
UIkit.on('afterready.uk.dom', function() {
var accordion = UIkit.accordion(UIkit.$('#myAccordion'), {collapse:false, showfirst: false});
//choose which number of accordion interest you, here we choose 1 and 3, index starts from 0
accordion.find('[data-wrapper]').each(function (index) {
if (index==0 || index==2)
accordion.toggleItem(UIkit.$(this), true, false); // animated true and collapse false
});
});
Here's working pen for you.
If I am not wrong, You are looking to keep by default first accordion. right? If yes you don't need to do any extra code for this. As Uikit as the solution itself.
You just have to put uk-open with first , take a look at below code and codepen.
<ul uk-accordion>
<li class="uk-open">
<a class="uk-accordion-title" href="#">Item 1</a>
<div class="uk-accordion-content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</li>
<li>
<a class="uk-accordion-title" href="#">Item 2</a>
<div class="uk-accordion-content">
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor reprehenderit.</p>
</div>
</li>
<li>
<a class="uk-accordion-title" href="#">Item 3</a>
<div class="uk-accordion-content">
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat proident.</p>
</div>
</li>
Look at CodePen too : Codepen

remove decoration tags aem sightly

How can I remove the decoration tags only in preview/publish mode in AEM sightly?
I have seen the question and answer: AEM/CQ: Conditional CSS class on decoration tag
This removes the decoration but stops me from editing the components because it removes the decoration in edit and design mode as well. What is the condition required so that it will only remove the decoration tags in preview/publish?
I have also seen that it is possible to add the following code into the activate method of my java-use class:
if (!getWcmMode().isEdit() && !getWcmMode().isDesign()) {
IncludeOptions.getOptions(getRequest(), true).setDecorationTagName("");
}
This removes all but one of the decoration tags see example below:
HTML in wcmmode=disabled without the above code in the activate method:
<ul class="timeline">
<div class="section timelineTag">
<div class="section timelineTag">
<div class="section timelineTag">
<li class="clear"></li>
</ul>
HTML in wcmmode=disabled with the above code in the activate method:
<ul class="timeline">
<div class="section timelineTag">
<li class="event" href="#">
<li class="event" href="#">
<li class="clear"></li>
</ul>
How can I remove the first decoration DIV tag in the ul as it does not disappear when I add the specified code to the activate method?
As requested here is a detailed look at the component in question (updated 07/05/2015):
Java Class
public class TimelineClass extends WCMUse {
#Override
public void activate() throws Exception {
//Remove default wrapping performed by AEM for the preview mode
if (!getWcmMode().isEdit() && !getWcmMode().isDesign()) {
IncludeOptions.getOptions(getRequest(), true).setDecorationTagName("");
}
}
}
HTML code:
- There are two components involved in this. First of all the container component that includes the ul tag
- Then the tag component which is dragged and dropped from the sidekick into the container to create, in publish, the lists shown above.
Container code:
<div class="az-timeline row">
<section class="small-12 columns">
<section class="wrapper">
<ul class="timeline">
<!-- /* The parsys where all of the timeline tags will be dropped */ -->
<div data-sly-resource="${'par-wrapper' # resourceType='foundation/components/parsys'}" data-sly-unwrap></div>
<li class="clear"></li>
</ul>
</section>
</section>
Tag component which is dragged and dropped into the container parsys above:
<li data-sly-use.timelineTag="TimelineClass" class="event" href="#">
<img style="width: 165px;" data-sly-test="${properties.outerImage}" alt="placeholder" src="${properties.outerImage}"/>
<article>
<h5>${properties.heading || 'Timeline heading'}</h5>
<h4>${properties.subheading || 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt labore molestias perspiciatis reiciendis.'}</h4>
<p>${properties.text || 'Sed molestie, mauris sit amet egestas malesuada, felis magna commodo urna, vel consequat lorem enim ac diam. Aenean eget ex vitae enim cursus facilisis ac feugiat nisl. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.'}</p>
<img style="height: 130px;" data-sly-test="${properties.innerImage}" alt="" src="${properties.innerImage}" />
<a data-sly-test="${properties.link}" class="az-sbButton" href="${properties.link}">${properties.linkText || 'More'}<span class="owi-az-linkIcon internal"></span></a>
</article>
</li>
Several of the tag components are dragged and dropped into the parsys in the container and the result in wcmmode=disabled is the second ul shown above with the first item in the list surrounded by a div tag
I haven't worked with the Sightly stuff yet, but I have had success removing the extra divs by assigning the property "cq:noDecoration" (Boolean set to true) on the component in the JCR. Try that and see if it helps.
if i understand you correctly and you want div.section.timelineTag to be here only in edit mode, then the code would be
<ul>
<div data-sly-test="${wcmmode.edit}" class="section timelineTag">
Use data-sly-unwrap. See this post and the referenced doc from adobe
http://www.aemmastery.com/2015/04/24/remove-div-tags-sightly/
"data-sly-unwrap: Removes the host element from the generated markup while retaining its content."
Another option, set cq:htmlTag to "":
http://dev.day.com/cemblog/en/experiencedelivers/2013/04/modify_the_auto-generateddivs.html
As Rampant suggested but make the timeline ul part of the component and try setting cq:htmlTag to a "ul" and give it a class timeline: and you can still edit the component and it does not mess with the display. http://dev.day.com/cemblog/en/experiencedelivers/2013/04/modify_the_auto-generateddivs.html
Possible workaround for the issue when you need conditional remove of the decoration tags in Sightly on example of edit / preview mode:
Create two child components for your component ("parent-component") - "edit-view" and "preview-view".
For "edit-view" component set cq:noDecoration="{Boolean}false"
For "preview-view" component set cq:noDecoration="{Boolean}true"
In parent-component.html add conditional rendering like:
<sly data-sly-test="${isEditMode}">
<sly data-sly-resource="${'editViewResourceName' # resourceType='yourapp/components/parent-component/edit-view'}"></sly>
</sly>
<sly data-sly-test="${isPreviewMode}">
<sly data-sly-resource="${'editViewResourceName' # resourceType='yourapp/components/parent-component/preview-view'}"></sly>
</sly>
Tips:
Add dialog only for "edit-view" component.
For "preview-view" component you can keep only .content.xml and preview-view.html
To avoid code duplication there is possibility to include "edit-view" into "preview-view" using construction like
<sly data-sly-resource="${currentNode.path # resourceType='yourapp/components/parent-component/edit-view'}"></sly>

tumblr customization - Show post details in modal

I've been modifying my tumblr page to show posts inside a modal.
I have added the modal but when I click on a post, the post details do not show up inside the modal.
I used a free theme that has the masonry grid applied and the blog shows a grid of posts.
Currently I have the modal outside {block:Posts}.
If I have the modal inside {block:Posts} I get 10 modals opening all on top of each other. Although post details do show inside the modal. (10 is the number of posts on current page).
If I have the modal inside {block:Photo} I get all the modals showing up inside the masonry grid.
Current state of my tumblr:
http://cnocle.tumblr.com/
What I want to acheive:
http://fifth-avenue-theme.tumblr.com/
Any help, suggestions, directions would be great!
Please let me know if I should post the code. It's long and I'm not sure if I should post it or not.
Code Below is the top section of the
thank you
<body>
<script type="text/javascript" src="http://static.tumblr.com/ek9ly4s/Yfzmx9hib/jquery.ms.js"></script>
<link href="http://static.tumblr.com/ek9ly4s/0WMmx9ghw/homemade-ii.css" rel="stylesheet">
<div id="header">
<div class="xnav">
{block:ifshowblogtitle} <img src="http://static.tumblr.com/ksc6s4f/dWtnk041m/cnocle-logo.png"/> // {/block:ifshowblogtitle}
{block:ifshowdescription}
{block:Description}<p>{Description}</p> //{/block:Description} {/block:ifshowdescription}
Home /
{block:AskEnabled}{text:Ask Title} /{/block:AskEnabled}
{block:ifLinkOneTitle}
{text:Link One Title} / {/block:ifLinkOneTitle}
{block:ifLinkTwoTitle}
{text:Link Two Title} / {/block:ifLinkTwoTitle}
{block:ifLinkThreeTitle}
{text:Link Three Title} / {/block:ifLinkThreeTitle}
{block:ifLinkFourTitle}
{text:Link Four Title} / {/block:ifLinkFourTitle}
{block:ifLinkFiveTitle}
{text:Link Five Title} / {/block:ifLinkFiveTitle}
{block:HasPages}{block:Pages}{Label} / {/block:Pages} {/block:HasPages}
{block:iftextonlineusercounter}
{text:text online user counter} /
{/block:iftextonlineusercounter}
Archive /
Theme
</div><div class="spacer"> </div></div>
<div id="content">
{block:Posts}
<div class = "autopagerize_page_element" >
<div class="entry">
{block:Photo}
{block:IndexPage}
<div class="photo">
<img src="{PhotoUrl-250}" alt="{PhotoAlt}"/>
</div>
{/block:IndexPage}
{/block:Photo}
{block:PermalinkPage}
<div style="display:block;">
<img src="{PhotoUrl-500}" alt="{PhotoAlt}"/>
{block:NoteCount}{NoteCountWithLabel}
<div style="margin-top:5px;"></div>{/block:NoteCount}
{block:HasTags} · {block:Tags} #{Tag}
<div style="margin-top:5px;"></div>{/block:Tags}{/block:hasTags}
{block:Caption}{Caption}{/block:Caption}{/block:PermalinkPage}
{block:PostNotes}
<div style="width:500px;height:250px;overflow-y:scroll;overflow-x:hidden;margin-left:-5px;">{PostNotes}</div>
{/block:PostNotes}
</div>
</div>
{/block:Posts}
<!--
Start of Modal
-->
<div class="modal-content drop-shadow">
<div class="product-desc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium adipisci aliquam corporis distinctio ea in incidunt ipsum molestiae molestias mollitia officiis possimus quis quod, ratione veritatis voluptate voluptatibus? A, amet.</div>
<div class="product-image"><img src="" alt="{PhotoAlt}" /></div>
</div>
<div class="modal-overlay"></div>
<!--
End of Modal
-->
<script type="text/javascript">
$(document).ready(function() {
$(".entry").click(function(){
var imgSrc = $(".photo").children("img").attr("src");
$(".product-image img").attr("src",imgSrc);
$(".modal-overlay").addClass("modal-show");
$(".modal-content").addClass("modal-content-show");
});
$(".btn-modal-close").click(function() {
$(".modal-overlay").removeClass("modal-show");
});
$(".modal-overlay").click(function() {
$(".modal-overlay").removeClass("modal-show");
$(".modal-content").removeClass("modal-content-show");
})
});
</script>
</div>

Detecting select slider change event in jQuery Mobile

What is a reliable way to detect change of a select slider in jQuery Mobile? I try to bind a handler to change event of the select control itself, but it fires on initial page display, and then fires multiple times on clicks, and sometimes even on hover (in desktop browser).
The minimal working example of this behaviour is posted here: http://jsfiddle.net/NPC42/mTjtt/3/
This is probably caused by jQuery Mobile adding more elements to style the select as the flip-toggle, but I can't find the recommended way to do it.
Any help is much appreciated.
May not be the slickest solution but it works
http://jsfiddle.net/mTjtt/4/
Live Example:
http://jsfiddle.net/KCQ4Z/14/
http://jsfiddle.net/phillpafford/KCQ4Z/70/ (using stopPropagation() )
JS:
$('#my-slider').change(function(event) {
event.stopPropagation();
var myswitch = $(this);
var show = myswitch[0].selectedIndex == 1 ? true:false;
if(show) {
$('#show-me').fadeIn('slow');
$('#first-me').fadeOut();
} else {
$('#first-me').fadeIn('slow');
$('#show-me').fadeOut();
}
});
HTML:
<div data-role="page" id="home" class="type-home">
<div data-role="content">
<div class="content-primary">
<p>The flip toggle switch is displayed like this:</p>
<div data-role="fieldcontain">
<label for="slider">Flip switch:</label>
<select name="slider" id="my-slider" data-role="slider">
<option value="off">Off</option>
<option value="on">On</option>
</select>
</div>
<div id="first-me">
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</p>
</div>
<div id="show-me" class="hidden">
<p>
Bacon ipsum dolor sit amet bresaola velit laboris bacon eiusmod. Id ex short ribs, dolor dolore rump pork belly beef ad ullamco salami labore aute ut. Jowl et in do, fatback jerky salami reprehenderit irure laboris pork loin commodo qui eu. Chuck tri-tip cupidatat, turkey sunt in anim jerky pork belly exercitation bacon. Eu corned beef qui adipisicing, ground round veniam turkey chicken incididunt deserunt. Proident t-bone chuck, non excepteur biltong elit in anim minim swine short loin magna do. Sint enim nisi, minim nulla tongue ut incididunt ground round.
</p>
</div>
</div>
</div>
</div>
UPDATE:
I have raised an issue/bug with jQM here:
https://github.com/jquery/jquery-mobile/issues/2188
Use this code,
$( ".mySliders" ).slider({
create: function (event, ui) {
$(this).bind('change', function () {
...
...
});
}
});
!Do not put type="range" to your input tags , put type="text" instead.
Since you are calling slider function manually.