Pass data-attribute value of clicked element to ajax settings - magnific-popup

For an implementation of Magnific Popup, I need to pass a post id to the ajax settings. The post id is stored in a data attribute of the element to which Magnific Popup is bound. I would like this to work:
html element:
<a data-id="412">Clicke me</a>
Javascript:
$('.element a').magnificPopup({
type: 'ajax',
ajax: {
settings: {
url: php_array.admin_ajax,
type: 'POST',
data: ({
action:'theme_post_example',
id: postId
})
}
}
});
Where postId is read from the data attribute.
Thanks in advance.

$('.element a').magnificPopup({
callbacks: {
elementParse: function(item){
postData = {
action :'theme_post_example',
id : $(item.el[0]).attr('data-id')
}
var mp = $.magnificPopup.instance;
mp.st.ajax.settings.data = postData;
}
},
type: 'ajax',
ajax: {
settings: {
url: php_array.admin_ajax,
type: 'POST'
}
}
});

Here is how to do it:
html:
<a class="modal" data-id="412" data-action="theme_post_example">Click me</a>
jquery:
$('a.modal').magnificPopup({
type: 'ajax',
ajax: {
settings: {
url : php_array.admin_ajax,
dataType : 'json'
}
},
callbacks: {
elementParse: function() {
this.st.ajax.settings.data = {
action : this.st.el.attr('data-action'),
id : this.st.el.attr('data-id')
}
}
},
parseAjax: function( response )
{
response.data = response.data.html;
}
});
php
function theme_post_example()
{
$id = isset( $_GET['id'] ) ? $_GET['id'] : false;
$html = '<div class="white-popup mfp-with-anim">';
/**
* generate your $html code here ...
*/
$html .= '</div>';
echo json_encode( array( "html" => $html ) );
die();
}

As this answer was the original question regarding inserting data into Magnific's ajax call, I'll post this here.
After many hours of trying to figure this out, you should know that if you're using a gallery with the ability to move between gallery items without closing the popup, using elementParse to set your AJAX data will fail when you visit an item after already viewing it (while the popup is still open).
This is because elementParse is wrapped up in a check that it makes detect if an item has already been 'parsed'. Here's a small explanation as to what happens:
Open gallery at item index 2.
Item has not been parsed yet, so it sets the parsed flag to true and runs the elementParse callback (in that order). Your callback sets the ajax options to fetch this item's data, all is well.
Move (right) to item index 3.
Same as above. The item has not been parsed, so it runs the callback. Your callback sets the data. It works.
Move (left) back to item index 2.
This time the item has been parsed. It skips re-parsing the item's element for assumed potential performance reasons.Your callback is not executed. Magnific's ajax data settings will remain the same as if it were item index 3.
The AJAX call is executed with the old settings, it returns with item index 3's data instead, which is rendered to the user. Magnific will believe it is on index 2, but it is rendering index 3's data.
To resolve this, you need to hook onto a callback which is always executed pre-ajax call, like beforeChange.
The main difference is that the current item isn't passed through into the callback. Fortunately, at this point, magnific has updated their pointers to the correct index. You need to fetch the current item's element by using:
var data = {}; // Your key-value data object for jQuery's $.ajax call.
// For non-closures, you can reference mfp's instance using
// $.magnificPopup.instance instead of 'this'.
// e.g.
// var mfp = $.magnificPopup.instance;
// var itemElement = mfp.items[mfp.index].el;
var itemElement = this.items[this.index].el;
// Set the ajax data settings directly.
if(typeof this.st.ajax.settings !== 'object') {
this.st.ajax.settings = {};
}
this.st.ajax.settings.data = data;
This answer can also be used as a suitable alternative to the currently highest voted, as it will work either way.

You may use open public method to open popup dynamically http://dimsemenov.com/plugins/magnific-popup/documentation.html#public_methods

postId = $(this).attr('data-id')
$(this) retrieve the current element (the link you clicked on), and attr the value of the specified attribute.

Related

Response.Redirect not changing URL

After clicking an element on my webpage, I get the expected behavior from Response.Redirect in the trace, the break point on the expected page gets hit and proceeds to process normally. However when I'd expect the new page to be loaded, the display in the browser is not changed. It looks and behaves like the click brought you back to the same page.
I've moved the redirect call out of a try-catch block, and have tried different combinations of true/false as the second parameter with HttpContext...CompleteRequest()
What might prevent a page from being loaded after a call from Response.Redirect and the Page_Load sub completes?
Edit:
The site uses css and javascript to create a hoverable dropdown menu containing self referencing links, see below. I have tried using Chrome's dev tools to see what the network was processing. As far as I can tell from reading the Network Tab the click was creating the correct call; status 200, type xhr. xhr was the only thing that I found odd, but it looks like this is simply a reference to ajax? This leaves me in the same position. I am telling the site to redirect to new url, and I see the network take a request for that url, but the url in the address bar doesn't change; not the displayed page.
$(document).on('click','.navigation', function () {
loadItems($(this).attr('id'), $(this).attr('itemName'));
return false;
}
);
var loadItems = function (id, itemName) {
var editInfor =
{
"method": "getChildItems",
"id": id
};
$.ajax
(
{
type: "POST",
url: $.url,
dataType: "json",
data: JSON.stringify(editInfor),
success: function (jsonReply) {
$("#chkEnabled").attr('checked', jsonReply.enabled)
if (jsonReply.method == 'getChildItems') {
$("#childrens").html('');
var html = '<table>'
if (jsonReply.successfull) {
$.each(jsonReply.children, function (i, item) {
html += '<tr><td><span class="children">' + item.text + '</span></td><td><a class="moveItemUp btn" href="#" id="moveItemUp' + item.id + '">Move Up <i class="icon-circle-arrow-up"></i></a> <a class="moveItemDown btn" href="#" id="moveItemDown' + item.id + '">Move Down <i class="icon-circle-arrow-down"></i></a></td><td>Remove</td></tr>'
});
}
html += '</table>'
$($.childrens).html(html);
}
}
}
);
Please try this:
$.mobile.changePage( "/Exmaple.aspx", {
transition: "pop"
});

Kendo UI autocomplete dynamically loading dBdata when typing

I am writing a kendo UI autocomplete widget. The requirement is EACH TIME when I type a letter after "minLength", the dataSource need to be dynamically loaded from dB EVERYTIME. One problem is that, when the dataSource load successfully in the first time, it stops loading data.
The code snippet is:
var data;
function getDataFromDb(){
// some code to grab dummyData from dB ...
return dummyData;
}
$("#someInputText").kendoAutoComplete({
minLength: 2,
dataTextField: "someField",
dataSource: getDataFromDb(),
filter: "startswith"
});
Thanks a lot.
More details on the post. In my situation, I don't use the readOption. The data comes from another ajax call like:
var data [];
//fire this ajax call when input string length comes to 4...
$.ajax({url: "some working url", success: function(result){
var data = result;
startKendoAutoComplete();
}
});
function startKendoAutoComplete(){
if( !$.isEmptyObject(data)) // set a breakPoint, have data
{
$("#inputText").kendoAutoComplete({
minLength: 4,
dataSource : data,
...
});
}
}
Also, the ajax call will be fired when the input string length comes to 4. However, the KendoAutoComplete doesn't start working....
Thanks a lot for your sugesstion.
If you init your dataSource with an array of object, your widget will work with this array only.
The first thing you'll have to create an dataSource object and set the serverFiltering property to true. Then, if you don't specify an url where the data will be fetched, you set you own transport.read function and from there you'll be able to implement your own logic. The read function will receive the readOption which will include all the relevant information to query tour data (top / skip / filter / sort ...). The readOptions will also provide a success function that should be used to return the value:
dataSource: {
serverFiltering: true,
transport: {
read: function (readOptions) {
readOptions.success(getDataFromDb(readOptions));
}
}
},

WinJS Listview shows undefined when navigating quickly

I have a WinJS application with listviews in which if quickly navigate between pages before the listview is fully loaded, the next page shows the listview with all elements in it bound as "undefined".
So say I have a hub page with a "to do" that is filtered to only show 6 items, and there is a header that navigates to the full "to do" page, when the hub page is displayed but before it is fully loaded I click on the header link to the "to do" page, the app then goes to the "to do" page, but the items show up with all the properties in the tile as "undefined".
I am using IndexedDB as my data store.
My home page code looks like this:
WinJS.UI.Pages.define("/pages/home/home.html", {
ready: function (element, options) {
WinJS.Utilities.query("a").listen("click", function (e) {
e.preventDefault();
WinJS.Navigation.navigate(e.currentTarget.href);
}, false);
viewModel = new HomeViewModel(element);
viewModel.load(); //loads from indexed db
},
//etc...
To Do Page:
WinJS.UI.Pages.define("/pages/ToDo/ToDo.html", {
ready: function (element, options) {
viewModel = new ToDoViewModel(element);
viewModel.load();
},
etc//
I know there isn't much to go off, but any ideas would be appreciated.
Also tips on how to debug something like this would be great.
Update
I narrowed it down to this one line from the Hub Page:
myLib.GetData(todaysDate, function (result) {
that.trendsModel.today = result;
WinJS.Binding.processAll(that.el.querySelector("#dataPanel"), that.trendsModel); //<--Right Here
});
If I remove that, then when I load the second page the data doesn't show as undefined. What is interesting is the data initially shows correctly on the second page and then it changes to "undefined".
Solution
My fix:
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it changes to undefined...Wow, what a doozy. I guess it makes sense but what a pain to find.
Hope it helps someone in the future :)
Your ToDoViewModel, and HomeViewModel need to be observable. This means they need to mix in from WinJS.Binding.mixin, and for the properties that you pull in asynchronously, they need to call this.notify("propertyName", newVal, oldVal) from the property setter.
Note that you need to have getter/setter properties. e.g.
var bindingBase = WinJS.Class.mix(function() {}, WinJS.Binding.mixin);
WinJS.Namespace.define("YourNamespace", {
ToDoViewModel: WinJS.Class.derive(bindingBase, function constructor() {
}, {
_titleStorage: "",
title: {
get: function() { return this._titleStorage; },
set: function(newValue) {
if(newValue === this._titleStorage) {
return;
}
var old = this._titleStorage;
this._titleStorage = newValue;
this.notify("title", newValue, old);
}
}
}),
});
myLib.GetData(todaysDate, function (result) {
var element = that.el.querySelector("#dataPanel");
that.trendsModel.today = result;
if(element) {
WinJS.Binding.processAll(element, that.trendsModel);
}
});
At the point when when the callback returns, I am already on the second page. So the selector was not found returning null. If you pass null to processAll it tries to bind the whole page which is why I was able to see the correct data for a second then it change to undefined...Wow, what doozy. I guess it makes sense but what a pain to find.

Simple store connected list for dojo

Is there a simpler list type than DataGrid that can be connected to a store for Dojo?
I would like the data abstraction of the store, but I don't need the header and cell stucture. I would like to be more flexible in the representation of the datalines, where maybe each line calls an function to get laid out...
You ask a really good question. I actually have a blog post that is still in draft form called "The DataGrid should not be your first option".
I have done a couple thing using the store to display data from a store in a repeated form.
I have manually built an html table using dom-construct and for each.
var table = dojo.create('table', {}, parentNode);
var tbody = dojo.create('tbody', {}, table); // a version of IE needs this or it won't render the table
store.fetch({ // this is a dojo.data.ItemFileReadStore, but you cana dapt to the dojo.Store API
query: {},
onComplete: function(itms) {
dojo.forEach(itms, function(itm, idx) {
var tr = dojo.create('tr', {}, tbody);
// use idx to set odd/even css class
// create tds and the data that goes in them
});
}
});
I have also created a repeater, where I have an html template in a string form and use that to instantiate html for each row.
var htmlTemplate = '<div>${name}</div>'; // assumes name is in the data item
store.fetch({ // this is a dojo.data.ItemFileReadStore, but you cana dapt to the dojo.Store API
query: {},
onComplete: function(itms) {
dojo.forEach(itms, function(itm, idx) {
var expandedHtml = dojo.replace(htmlTemplate, itm);
// use dojo.place to put the html where you want it
});
}
});
You could also have a widget that you instantiate for each item.

jquery .live on form submit not picking up dynamically added inputs

when my ajaxupload script finishes it adds a read-only input w/ the value of the image's URL.
it is a long script, but i think this is the relevant part that fires on successful completion:
var location = '<div id="'+ID+'_location" class="img_location">' + '<input name="'+ID+'" class="location regular-text" type="text" size="50" readonly="readonly" value="'+response+'" />';
$(container).append(location).show(); //create readonly input
$(container) is defined just as the parent div of the upload button. that part seems to work... the image is uploaded, it is saved properly, and the input w/ the image's location is added to to the DOM. but i've discovered a bug that if I click my SAVE button (which triggers my ajax save function) then this new input is NOT captured.
here is my save function:
$('form#childoptions').live('submit', function(e) {
e.preventDefault();
var values = $(this).serialize();
alert(values);
var data = {
action: 'save_function',
type : 'save',
_nonce: '<?php echo $nonce; ?>',
formdata: values
};
$.post(ajaxurl, data, function(response) {
//alert(response);
if(response == 1) {
show_message(1);
t = setTimeout('fade_message()', 2000);
} else {
show_message(99);
t = setTimeout('fade_message()', 2000);
}
});
//return false;
});
only the new input is not captured. the rest works properly. there is also no problem if i refresh in between as I presume the input is part of the DOM. which is why i thought to use .live. i thought i had solved the issue twice- 1. i wasn't using a "name" on the dynamic input and 2. i wasn't using .live on the form. but now i am doing both and not getting anywhere.
all help is much appreciated. let me know if there is more information I can provide.
It appears that your using live on the whole form, not on inputs. So the live event binding would try to pickup new forms with id childoptions. This won't work. You'd be better off using bind() instead. Have you tried:
$('form#childoptions').bind('submit', function(e) {…}
I'm curious if this will fix your issue.