Using data-attributes inside fancyBox options - javascript

Have searched for a solution to this but am coming up blank. I'm trying to set a data attribute and access it within the fancyBox options.
My anchor links looks like this:
<a class="expand" rel="gallery" href="/assets/images/larger-image.png" data-source="Some string" data-id="Some number">
<img src="blah.jpg" />
</a>
And my JS:
$(".expand").fancybox({
'padding' : 0,
'tpl' : {
image : '<img class="fancybox-image" src="{href}" alt="" />'
}
});
What I'd like to be able to do is access those data-attributes inside the tpl option.
$(".expand").fancybox({
'padding' : 0,
'tpl' : {
image : '<h2>' + $(this.element).data('source') + '</h2><img class="fancybox-image" src="{href}" alt="" /><h3>' + $(this.element).data('id') + '</h3>'
}
});
I can't access this.element in that context; is there an elegant way to achieve this?

Well, the tpl is used to format specific elements of the fancybox structure so this
'tpl' : {
image : '<h2>' + $(this.element).data('source') + '</h2><img class="fancybox-image" src="{href}" alt="" /><h3>' + $(this.element).data('id') + '</h3>'
}
it's a bit odd since you are adding elements that are not part of the image template (normally you would use it to add classes or other attributes, etc.)
Anyways, if this is what you want, you first need to use a fancybox callback to have access to the data attributes ( $(this.element) can only be accessed inside a callback ).
Then you may need to use the jQuery.extend() method to modify the fancybox template on the fly (from within the afterLoad callback) like :
$(".expand").fancybox({
afterLoad: function () {
$.extend(this, {
tpl: {
image: '<h2>' + $(this.element).data('source') + '</h2><img class="fancybox-image" src="{href}" alt="" /><h3>' + $(this.element).data('id') + '</h3>'
}
});
}
});
See JSFIDDLE

Related

onclick events don't work for ajax appended html using classic asp with Prestashop static html files [duplicate]

This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 4 years ago.
I have been assigned to update a classic asp website with a Prestashop template called Autotune Responsive Prestashop Theme. My client wants all the ajax bells and whistles they see online in Template Monster. Template Monster made static html files for my client from this template which includes all the custom Prestashop javascript libraries. So far I am unable to use these custom Prestashop jquery/ajax libaries as they were intended so I have to write my own code to paginate, add to cart, show item popup, etc. Everything works great except for appending html. For example, pagination. When I view a list of parts in grid view and I click to append nine more parts, the html gets appended OK but onclick events to the Add To Cart button and "eye" icon popup are dead for the new items that were appended. Mouse over events are OK. Same issue when I append html to the cart popup - I see the added cart items in the cart popup but the "x" (delete) won't work when clicked although the color changes when moused over. It's as if I need to update something after appending. I'm stumped. Here is the pagination code:
$(function() {
$('#infiniteScrollMore').click(function(){
var numItems = parseInt($('#NumItems').text());
var pageNbr = parseInt($('#PageNbr').text()) + 1;
$('#PageNbr').text(pageNbr);
$.get('AppendParts.asp?PageNbr=' + pageNbr + '&NumItems=' + numItems,function (data) {
$('.product_list').append(data);
numNextItems = parseInt(numItems) - (parseInt(pageNbr) * 9);
if (parseInt(numNextItems) >= 9) numNextItems = 9;
setTimeout(function(){$('#NumNextItems').text(' (' + numNextItems + ')')},2000);
if ((parseInt(pageNbr) * 9) >= parseInt(numItems))
{
$('#infiniteScrollMore').hide();
setTimeout(function(){$('#NewSearchButton').show();},2000);
}
});
});
});
I am just using .append to append html to the product_list ul. AppendParts.asp writes the html, which is...
<li class="ajax_block_product">
<div class="product-container" itemscope itemtype="https://schema.org/Product">
<div class="left-block">
<div class="product-image-container">
<div class="tmproductlistgallery rollover">
<div class="tmproductlistgallery-images opacity">
<a class="product_img_link cover-image" href="product.asp?PartNbr=<%=pageCache("PartNbr")%>&StockNbr=<%=pageCache("StockNbr")%>&ProductCode=<%=pageCache("ProductCode")%>&MachineType=<%=pageCache("MachineType")%>&Model=<%=pageCache("Model")%>&Category=<%=pageCache("Category")%>&SubCategory=<%=pageCache("SubCategory")%>" title="<%=pageCache("Description") & " " & pageCache("Make") & " " & pageCache("PartNbr") & " " & pageCache("Class")%>" itemprop="url">
<img class="img-responsive" src="http://<%=theImage%>" alt="" title="<%=pageCache("Description") & " " & pageCache("Make") & " " & pageCache("PartNbr") & " " & pageCache("Class")%>">
</a>
<a class="product_img_link rollover-hover" href="product.asp?PartNbr=<%=pageCache("PartNbr")%>&StockNbr=<%=pageCache("StockNbr")%>&ProductCode=<%=pageCache("ProductCode")%>&MachineType=<%=pageCache("MachineType")%>&Model=<%=pageCache("Model")&Category=<%=pageCache("Category")%>&SubCategory=<%=pageCache("SubCategory")" title="<%=pageCache("Description") & " " & pageCache("Make") & " " & pageCache("PartNbr") & " " & pageCache("Class")%>" itemprop="url">
<img class="img-responsive" src="http://<%=theImage%>" alt="" title="<%=pageCache("Description") & " " & pageCache("Make") & " " & pageCache("PartNbr") & " " & pageCache("Class")%>">
</a>
</div>
</div>
<div class="functional-buttons">
<div class="qv-wrap">
<a class="quick-view" data-id="<%=pageCache("ProductCode") & ":" & pageCache("StockNbr") & ":" & pageCache("PartNbr")%>" href="#" onclick="return false;" data-fancybox-type="ajax" data-type="ajax" data-href="#" title="Quick View"></a>
</div>
<div class="compare">
<a class="add_to_compare" href="product.asp?PartNbr=<%=pageCache("PartNbr")%>&StockNbr=<%=pageCache("StockNbr")%>&ProductCode=<%=pageCache("ProductCode")%>&MachineType=<%=pageCache("MachineType")%>&Model=<%=pageCache("Model")%>&Category=<%=pageCache("Category")%>&SubCategory=<%=pageCache("SubCategory")%>" data-id-product="<%=pageCache("ProductCode") & ":" & pageCache("StockNbr") & ":" & pageCache("PartNbr")%>" title="Detailed View"></a>
</div>
</div>
... abbreviated a bit. Here is the fancybox code:
$(function() {
$('.quick-view').click(function(){
var idStrArray = $(this).attr('data-id');
var idStr = idStrArray.split(':');
var productCode = idStr[0];
var stockNbr = idStr[1];
var partNbr = idStr[2];
$.fancybox({
'closeClick': true,
'hideOnContentClick': true,
'padding': 0,
'width': 1021,
'autoDimensions': false,
'height': 500,
'type': 'iframe',
'tpl': {wrap: '<div class="fancybox-wrap fancybox-quick-view" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>'},
'href': 'product-popup.asp?PartNbr=' + partNbr + '&ProductCode=' + productCode + '&StockNbr=' + stockNbr,
'beforeClose': function() {}
}
});
});
});
What am I missing?
You have to the event trigger like this -
$( "body" ).on( "click", "p", function() {
alert( $( this ).text() );
});
Use jQuery .on() method. Read the doc

Tagfield with html encoded displayField in Extjs 6

Before upgrading to Extjs 6 we were using a tagfield component where its displayField was Ext.String.htmlEncode('description') where description was the description field of the store's record. This field doesn't only contain simple text but instead is in the form of: <img src="link..." style="..."/>&nbspRECORD_DESCRIPTION. Using the htmlEncode function it would actually render the tagfield's records with the linked image and the record's description.
However after upgrading to version 6 this stopped working. It now just produces the full text instead of rendering the image. Its like htmlEncode stopped working all of a sudden. The thing is that in an ItemSelector field where we do the same thing everything works perfectly using the exact same method. Did they break the tagfield component so as to not be able to show html?
Regardless, how can I reproduce what I did before? I tried with displayTpl config but it doesn't seem to work.
Instead of Ext.String.htmlEncode('description') try just 'description' in displayField. DisplayField affects what you see when you are selecting, and for that, it will display your HTML. It also affects how it displays the selections you have made, and there doesn't seem to be a way to display HTML there. It displays as plain text. There is another attribute, labelTpl, that formats the items you have already selected. You can use that to display just the names of things you have already selected. (LabelTpl used to display formatted HTML, but doesn't in ExtJs6.) Suppose your store record also had a 'name' field that is just plain text; you would put that inside curly braces:
xtype:'tagfield',
displayField: 'description',
labelTpl: '{name}',
...
Then you will get formatted HTML while making a selection, and plain text in the selected items. That's the best I've come up with so far.
Using ExtJS 6.5.3
This is the best I was able to figure out for a tag field in terms of creating a complex display statement for both list and tags.
The display supports CSS and other HTML tags
The labelTpl does not support anything but plain text, but you can override it's x-tagfield-item-text style however, it's all or nothing.
{
cls: "triggerstagfield",
displayField: '[(values.key != "all") ? values.label + " (<b>" + values.key + "</b>)" : values.label]',
labelTpl: '{[(values.key != "all") ? values.label + " (" + values.key + ")" : values.label]}',
valueField: "key",
store: [{
"key": "all",
"label": "All"
}, {
"key": "880",
"label": "International House of Pancakes"
}]
},
and this is the CSS
.triggerstagfield .x-tagfield-item-text {
font-weight: bold;
font-size: 0.9em;
}
I worked around it by extending the built in tag field, overriding the function getMultiSelectItemMarkup. In that function I removed the call to Ext.String.htmlEncode on the label.
With this you can use
{
xtype: 'tagfieldhtmllabel',
labelTpl: '<span style="background-color:#{colorbg};">{name}</span>',
...
}
This is the code that works on Ext 6.2.1
Ext.define("Private.ui.TagFieldHtmlLabel", {
extend: 'Ext.form.field.Tag',
alias: 'widget.tagfieldhtmllabel',
// TODO EXT UPGRADE. WHEN UPGRADING FROM 6.2.1 update this
getMultiSelectItemMarkup: function() {
var me = this,
childElCls = (me._getChildElCls && me._getChildElCls()) || '';
// hook for rtl cls
if (!me.multiSelectItemTpl) {
if (!me.labelTpl) {
me.labelTpl = '{' + me.displayField + '}';
}
me.labelTpl = me.lookupTpl('labelTpl');
if (me.tipTpl) {
me.tipTpl = me.lookupTpl('tipTpl');
}
me.multiSelectItemTpl = new Ext.XTemplate([
'<tpl for=".">',
'<li data-selectionIndex="{[xindex - 1]}" data-recordId="{internalId}" role="presentation" class="' + me.tagItemCls + childElCls,
'<tpl if="this.isSelected(values)">',
' ' + me.tagSelectedCls,
'</tpl>',
'{%',
'values = values.data;',
'%}',
me.tipTpl ? '" data-qtip="{[this.getTip(values)]}">' : '">',
'<div role="presentation" class="' + me.tagItemTextCls + '">{[this.getItemLabel(values)]}</div>',
'<div role="presentation" class="' + me.tagItemCloseCls + childElCls + '"></div>',
'</li>',
'</tpl>',
{
isSelected: function(rec) {
return me.selectionModel.isSelected(rec);
},
getItemLabel: function(values) {
// UPGRADE - removed htmlEncode here
return me.labelTpl.apply(values);
},
getTip: function(values) {
return Ext.String.htmlEncode(me.tipTpl.apply(values));
},
strict: true
}
]);
}
if (!me.multiSelectItemTpl.isTemplate) {
me.multiSelectItemTpl = this.lookupTpl('multiSelectItemTpl');
}
return me.multiSelectItemTpl.apply(me.valueCollection.getRange());
}
});

Change a directive template using ng-click

I have a few buttons with ng-click in a controller and I want to change the a directive template when I click on a button. What is the best way to achieve this? (I will later use a slide in effect of the element)
Directive:
myModule.directive('foo', function() {
return {
scope: {
templateType: '#'
},
template: '<div ng-if="templateType == \'a\'">' +
' this is template A ' +
'</div>' +
'<div ng-if="templateType == \'b\'">' +
' this is template B ' +
'</div>'
};
});
Template:
<foo template-type="{{ templateType }}"></foo>
<a ng-click="templateType = 'b'" href="">Set template to b</a>
Controller:
$scope.templateType = 'a';
You can extend the example provided by #JB Nizet and use ng-include to swap templates, and managing larger size templates becomes easier.
myModule.directive('foo', function() {
return {
scope: {
templateType: '#'
},
template: '<div ng-include="\'/templateRoot/\' + templateType">'+
'</div>'
};
});
Now you can create separate template files and make them available on specific url (in this case /templateroot/a or /templateroot/b)

Wait for data to load

I am trying to add a custom tweet button on my angular app. Here is the code I use to do it:
HTML:
<a href="" class="retweet" retweet target="_blank" data-info="{{ data.name }}">
Tweet
</a>
JS:
myApp.directive('retweet', function(){
return function(scope, elm, attrs){
var API_URL = "http://cdn.api.twitter.com/1/urls/count.json",
TWEET_URL = "https://twitter.com/intent/tweet";
elm.each(function() {
var elem = $(this),
// Use current page URL as default link
url = encodeURIComponent(elem.attr("data-url") || document.location.href),
// Use page title as default tweet message
text = elem.attr("data-info") || document.title,
via = elem.attr("data-via") || "",
related = encodeURIComponent(elem.attr("data-related")) || "",
hashtags = encodeURIComponent(elem.attr("data-hashtags")) || "";
console.log(elem.attr("data-job"));
// Set href to tweet page
elem.attr({
href: TWEET_URL + "?hashtags=" + hashtags + "&original_referer=" +
encodeURIComponent(document.location.href) + "&related=" + related +
"&source=tweetbutton&text=" + text + "&url=" + url + "&via=" + via,
target: "_blank",
onclick: "return !window.open(this.href, 'Google', 'width=500,height=500')"
});
});
}
})
My problem here is that the js fetch the data before the data is even loaded in the page. Therefere the "text" variable is set to {{ data.test }} rather than the actual data which gets loaded later on the page.
How can I make sure the data is loaded on time?
Many thanks
You can use ng-cloak to prevent rendering uncompiled data:
<a href="" class="retweet" retweet target="_blank" data-info="{{ data.name }}" ng-cloak>
Tweet
</a>
You can read more about this here: http://docs.angularjs.org/api/ng/directive/ngCloak
Can you try to use $scope.data.name directly instead of elem.attr("data-info")?
Or you can add the expression as a property:
<a href ... data-info="$scope.data.name">
And use it like this:
scope.$eval(attrs.dataInfo);

Fancybox will not use content passed via javascript

Using jquery 1.10.2, fancybox 2.1.5
I'm trying to pass fancybox the "content: data" via javascript but its not working. Yet if I console.log the data variable it shows me valid HTML/text, but fancybox refuses to use it.
<div class="item">
<h4 class="choice">launch modal</h4>
<div class="detail">
This should show up in my <b>fancybox</b>!
</div><!--.detail-->
</div><!--.item-->
$('.choice').each(function(i, elem){
$(elem).siblings('.detail').wrap('<div style="display:none"></div>');
});
$(".choice").fancybox({
maxWidth: 800,
content: 'replace this text',
beforeShow: function(){
var title = $(this.element).text();
var data = $(this.element).parent().find('.detail').html();
console.log('this=' + this + ' | title=' + title + ' | data=' + data);//DEBUG
this.content = data;
}
});
The console log shows clearly that its got the data html content, but fancybox refuses to use it. I've wrapped it in another div with display:none since their site says to do that for whatever reason.
To build your content inside the callback, use afterLoad instead, otherwise the content option will have preference over this.content within any other callback :
$(".choice").fancybox({
maxWidth: 800,
content: 'replace this text',
afterLoad: function () {
var title = $(this.element).text();
var data = $(this.element).parent().find('.detail').html();
console.log('this=' + this + ' | title=' + title + ' | data=' + data); //DEBUG
this.content = data;
}
});
See JSFIDDLE
Note: you can also build/replace the title as in your code above like this.title = title;

Categories

Resources