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;
Related
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
In knockoutjs I have a custom component loader in which I do some logic. Basically I want to alter the template from the createViewModel function. I know there's the componentInfo.templateNodes but I don't know what to do with it.
The reason I want to alter it in the createViewModel function is because the createViewModel function is called every time a component is shown.
Ahwell, code says way more than words so check it out yourself down here.
ko.components.loaders.unshift({
getConfig: function (name, callback) {
var component; // The component gets loaded somewhere. (Sadly I can't alter the template here because it is only called once.)
callback({
viewModel: {
createViewModel: function (params, componentInfo) {
// Load these parameters somewhere
var args;
var location;
// I'd love to add these two items before and after my template.
var before = "<div data-bind=\"with: " + location + "\">";
var after = "</div>";
// Construct a viewModel with the data provided.
return app.core.helpers.construct(component.viewModel, location, args);
}
},
template: component.template
});
},
loadTemplate: function (name, template, callback) {
// Get the location again.
var location;
// I just want to load the template while applying the correct binding scope from the createViewModel.
var templateString = "<!-- ko stopBinding: true -->\n<!-- ko with: " + location + " -->\n" + template + "\n<!-- /ko -->\n<!-- /ko -->";
// Just let it load.
ko.components.defaultLoader.loadTemplate(name, templateString, callback);
}
});
I managed to create a working solution (although in its infancy). As I still don't know how to add template code to the componentInfo I discovered it is possible to edit the things available in the componentInfo. (See the solution below)
ko.components.loaders.unshift({
getConfig: function (name, callback) {
var component;
callback({
viewModel: {
createViewModel: function (params, componentInfo) {
// Load these parameters somewhere
var args;
var location;
/*
* The first one is the element we're binding on. The next sibling is the element we probably want to alter.
*/
if (componentInfo.element.nextSibling.nodeType == 8 && componentInfo.element.nextSibling.nodeValue.indexOf("[injectNamespace]") > -1) {
componentInfo.element.nextSibling.nodeValue = "ko with: models." + name.replace('/', '.');
}
return app.core.helpers.construct(component.viewModel, location, args);
}
},
template: component.template
});
},
loadTemplate: function (name, template, callback) {
var templateString = "<!-- ko with: [injectNamespace] -->\n" + template + "\n<!-- /ko -->";
ko.components.defaultLoader.loadTemplate(name, templateString, callback);
}
});
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
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);
My html document will have div container which gets populated with handlebars template name 'relatedVideosTemplate' on execution.
<div id="relVideos"></div>
Below anonymous function will make ajax request and pass the data to handlebar template which loops over all items in data object to construct related videos UI.
(function(options) {
var defualt = {
defaultThumb: "/url/to/default/thumbnail/",
apiURL: '/path/to/api/url'
};
options = options || {};
options = $.extend(true, defaults, options);
// handlebars template for the related video carousel
var relatedVideosTemplate : "<h3>Related Videos</h3>" +
"<ul class=\"related-videos\">" +
"{{#foreach items}}<li class=\"video {{#if $last}} last{{/if}}\">" +
"<a href=\"/video/?videoid={{id}}\" class=\"image\">" +
"<img alt=\"{{name}}\" {{#if videoStillURL}}src=\"{{videoStillURL}}\"{{else}}src=\"{{defaultVideoThumb}}\"{{/if}} width=\"90\" height=\"75\" data-id=\"{{id}}\" onerror=\"this.src='{{defaultVideoThumb}}';\" />" +
"<span class=\"video-time\">{{length}}</span></a>" +
"<div class=\"info\"><h5>{{name}}</h5>" +
"<span class=\"published-date\">{{publishedDate}}</span>" +
"{{#if playsTotal}}<span class=\"video-views\">{{playsTotal}} views</span>{{/if}}" +
"</div></li>{{/foreach}}" +
"</ul>",
template, relVideosHTML;
$.ajax({
url: options.apiURL,
success: function(data) {
template = Handlebars.compile(relatedVideosTemplate);
relVideosHTML = template(data);
$("#relVideos").html( relVideosHTML );
}
});
});
Its very likely the video still image (thumbnail) for some videos will return 404 and in that case I use onerror event on image tag to replace it with default thumbnail.
Is there a way to pass this default thumbnal value as object to handlebars block expression template ?
I don't want to amend the data object to have 'defaultThumb' property for all items. Like below...
for ( i = 0, max = data.items.length; i < max; i++) {
// Adding new property to each item in data object
data.items[i].defaultThumb = options.defaultThumb;
};
It seems to me amending data property in above loop is non efficient as the defaultThumb is same across all videos which return 404 for still(thumb) image.
Why not set defaultVideoThumb once at the top level and then reference it as {{../defaultVideoThumb}} inside the loop? Something like this in the template:
<img
{{#if videoStillURL}}src="{{videoStillURL}}"{{else}}src="{{../defaultVideoThumb}}"{{/if}}
width="90" height="75"
onerror="this.src='{{../defaultVideoThumb}}'
>
and then in the JavaScript:
data.defaultVideoThumb = '...';
var html = template(data);
Demo: http://jsfiddle.net/ambiguous/9ecx3/