I'm a begginer jQuery dev, and I'm using the jQuery UI dialog to show up properties of an object (whatever).
var $dialog = $('<div></div>')
.html('This dialog will show every time!')
.dialog({
autoOpen: false,
title: 'Properties'
});
So this is the dialog, and let's say I have a FOR structure in which I add properties (p tags) and for some of those properties I want a button.
var dialogHtml = "";
var dialog_buttons = {};
for (var key in d.properties){
var str;
var str = '<p>' + something + '</p>';
if (condition){
dialog_buttons[key] = function()
{ functionName(key); };
}
dialogHtml = dialogHtml + str;
}
$dialog.dialog( "option", "buttons", dialog_buttons );
$dialog.dialog('open');
And somewhere else I have the function:
function functionName(key){
// something something
}
This is where I have the problem: the key variable that's passed to the function... when the button is called the key is the last value from the iteration.
Let's say we have keys 1, 2, 3, 4 then when the button is clicked, the key parameter will be 4.
I want when I click a button from the dialog, to know which button was pressed.
Can anybody help me?
Thanks!
Using the event data from the click event (see here)
$('#btn').click(function(e) {
functionName(e.target);
});
Explanation of Event.Target
Related
I have a sortable list in React which is powered by jQuery UI. When I drag and drop an item in the list, I want to update the array so that the new order of the list is stored there. Then re-render the page with the updated array. i.e. this.setState({data: _todoList});
Currently, when you drag and drop an item, jQuery UI DnD works, but the position of the item in the UI does not change, even though the page re-renders with the updated array. i.e. in the UI, the item reverts to where it used to be in the list, even though the array that defines its placement has updated successfully.
If you drag and drop the item twice, then it moves to the correct position.
// Enable jQuery UI Sortable functionality
$(function() {
$('.bank-entries').sortable({
axis: "y",
containment: "parent",
tolerance: "pointer",
revert: 150,
start: function (event, ui) {
ui.item.indexAtStart = ui.item.index();
},
stop: function (event, ui) {
var data = {
indexStart: ui.item.indexAtStart,
indexStop: ui.item.index(),
accountType: "bank"
};
AppActions.sortIndexes(data);
},
});
});
// This is the array that holds the positions of the list items
var _todoItems = {bank: []};
var AppStore = assign({}, EventEmitter.prototype, {
getTodoItems: function() {
return _todoItems;
},
emitChange: function(change) {
this.emit(change);
},
addChangeListener: function(callback) {
this.on(AppConstants.CHANGE_EVENT, callback);
},
sortTodo: function(todo) {
// Dynamically choose which Account to target
targetClass = '.' + todo.accountType + '-entries';
// Define the account type
var accountType = todo.accountType;
// Loop through the list in the UI and update the arrayIndexes
// of items that have been dragged and dropped to a new location
// newIndex is 0-based, but arrayIndex isn't, hence the crazy math
$(targetClass).children('form').each(function(newIndex) {
var arrayIndex = Number($(this).attr('data-array-index'));
if (newIndex + 1 !== arrayIndex) {
// Update the arrayIndex of the element
_todoItems[accountType][arrayIndex-1].accountData.arrayIndex = newIndex + 1;
}
});
// Sort the array so that updated array items move to their correct positions
_todoItems[accountType].sort(function(a, b){
if (a.accountData.arrayIndex > b.accountData.arrayIndex) {
return 1;
}
if (a.accountData.arrayIndex < b.accountData.arrayIndex) {
return -1;
}
// a must be equal to b
return 0;
});
// Fire an event that re-renders the UI with the new array
AppStore.emitChange(AppConstants.CHANGE_EVENT);
},
}
function getAccounts() {
return { data: AppStore.getTodoItems() }
}
var Account = React.createClass({
getInitialState: function(){
return getAccounts();
},
componentWillMount: function(){
AppStore.addChangeListener(this._onChange);
// Fires action that triggers the initial load
AppActions.loadComponentData();
},
_onChange: function() {
console.log('change event fired');
this.setState(getAccounts());
},
render: function(){
return (
<div className="component-wrapper">
<Bank data={this.state.data} />
</div>
)
}
});
The trick is to call sortable('cancel') in the stop event of the Sortable, then let React update the DOM.
componentDidMount() {
this.domItems = jQuery(React.findDOMNode(this.refs["items"]))
this.domItems.sortable({
stop: (event, ui) => {
// get the array of new index (http://api.jqueryui.com/sortable/#method-toArray)
const reorderedIndexes = this.domItems.sortable('toArray', {attribute: 'data-sortable'})
// cancel the sort so the DOM is untouched
this.domItems.sortable('cancel')
// Update the store and let React update (here, using Flux)
Actions.updateItems(Immutable.List(reorderedIndexes.map( idx => this.state.items.get(Number(idx)))))
}
})
}
The reason jQuery UI Sortable doesn't work with React is because it directly mutates the DOM, which is a big no no in React.
To make it work, you would have to modify jQuery UI Sortable so that you keep the DnD functionality, but when you drop the element, it does not modify the DOM. Instead, it could fire an event which triggers a React render with the new position of the elements.
Since React uses a Virtual DOM, you have to use the function React.findDOMNode() to access an actual DOM element.
I would call the jQuery UI function inside the componentDidMount method of your component because your element has to be already rendered to be accessible.
// You have to add a ref attribute to the element with the '.bank-entries' class
$( React.findDOMNode( this.refs.bank_entries_ref ) ).sortable( /.../ );
Documentation - Working with the browser (everything you need to know is here)
Hope that makes sense and resolves your issue
I am building a single page application using jQuery Mobile.
In the header I have a "menu" button that opens a popup with a listview.
I would like to define this popup dialog and reuse it for all pages.
Reusing a popup outside a page works fine, but listview inside the popup does not get enhanced (because listview internally uses parent page to resolve links included in the list).
Question: is it possible to use a listview widget outside of a page? (I do understand that I might have to specify a base url for this to work, but I don't think that will be a problem).
No, its not possible. When you create a dynamic popup, which doesnt reside in a single page, IT WILL WORK, because popups were never meant to be used/page. But, listview on the other hand, requires the list to lie in a parent page. The refresh method of listview expects it to be in parent. Look at this function which is called when a listview refresh happens :
_createSubPages: function () {
var parentList = this.element,
parentPage = parentList.closest(".ui-page"), //<-- This line
parentUrl = parentPage.jqmData("url"),
parentId = parentUrl || parentPage[0][$.expando],
parentListId = parentList.attr("id"),
o = this.options,
dns = "data-" + $.mobile.ns,
self = this,
persistentFooterID = parentPage.find(":jqmData(role='footer')").jqmData("id"),
hasSubPages;
// blah blee blah
}).listview();
See the second line in the function. It expects a page to be there. Tough luck bro :)
PS : This is the closest i could get : http://jsfiddle.net/hungerpain/8qq62/1/
EDIT
Here's a hacky way. You could dynamically create a hidden <span/> in your data-role=page div and add the <ul/> in it. Then you could refresh it, after which you could move it to the dynamic popup. Then you'll have to remove that hidden span element. Here's the code :
$.extend({
"makePopup": function (array) { //you could add more if you want here, such as callbacks to the click function of the button,etc.
var $popup;
//creat popup element
$popup = $("<div/>", {
"data-role": "popup",
"data-theme": "a",
"data-overlay-theme": "a",
"data-transition": "pop"
}).popup();
//create list
$list = $("<ul/>", {
"data-role": "listview",
"id": "templist"
}).html(function () {
var li = [];
for (var i = 0; i < array.length; i++) {
li.push($("<li/>").html(array[i]));
}
return li;
})
//create close element
var $close = $("<a/>", {
"data-role": "button",
"html": "Close",
"href": "#",
"data-theme": "a"
}).on("click", function () {
//click event of close element
$(this).closest("[data-role=popup]").popup("close");
}).buttonMarkup();
//add a span to page, refresh list, etc
$.mobile.activePage.append("<span id='temp'></span>").find("#temp").hide().append($list).promise().done(function () {
$(this).find("#templist").listview().listview("refresh");
});
//create content div - makes a nice jQM page structure.
var $content = $("<div/>", {
"data-role": "content",
//move li to popup
}).append($("#temp").find("#templist"), $close);
//remove span
$("#temp").remove();
//append $close to $content, then append $content to $popup
$content.appendTo($popup)
return $popup;
}
});
And you could pass an array to this :
$.makePopup(["Sweet Child 'O Mine", "Summer of '69", "Smoke in the Water", "Enter Sandman", "I thought I've seen everything"]).popup("open");
Here's an updated demo : http://jsfiddle.net/hungerpain/8qq62/7/
But obviously this is hacky.
I want to create "CRUD" functions by calling a modal form by clicking on a row in Datatables.
I've been at this for hours traversing through each step of my code and it seems I'm getting a conflict between my JQ-UI and Datatables. I found several examples, including the Datatables example for "live" functions, where you can initialize a table and call a simple jquery function.
I'm using:
code.jquery.com/jquery-1.9.1.js
code.jquery.com/ui/1.10.2/jquery-ui.js
../DataTables-1.9.4/media/js/jquery.dataTables.js
This example will give me the cursor, then makes the table "jump" across the page.
Does anyone have a working example or a fiddle I can experiment with?
function openDialog() {
$("#dialog-modal").dialog({
height: 140,
modal: true
});
}
/* Init DataTables */
$('#example').dataTable();
/* Add events */
$('#example tbody tr').on('click', function () {
$('#example tbody tr').css('cursor', 'pointer');
var sTitle;
var nTds = $('td', this);
var sBrowser = $(nTds[1]).text();
var sGrade = $(nTds[4]).text();
/*
if (sGrade == "A")
sTitle = sBrowser + ' will provide a first class (A) level of CSS support.';
else if (sGrade == "C")
sTitle = sBrowser + ' will provide a core (C) level of CSS support.';
else if (sGrade == "X")
sTitle = sBrowser + ' does not provide CSS support or has a broken implementation. Block CSS.';
else
sTitle = sBrowser + ' will provide an undefined level of CSS support.';
*/
openDialog();
//alert( sTitle )
});
A little sleep and another stab at this yielded a solution that at least solves the Datatable Dialog issue, I'll have to assume that any other issues I was having lies the other add-ins that I included. So to me this is solved.
The answer was 99% in this post - thanks to the author for the great working example.
I modified their link solution, combined with Datatables "live" solution example with variables, and was able to successfully pass data to a working dialog that works with pagination as the previous link explains.
This set up would allow me to create JQuery-UI Modal Forms, pass the ID from mySQL table column, and execute the form that's handing the Server Side PHP CRUD functions I needed.
(I can't take credit for any part of this, other than time spent making sure it worked).
The working example is taken straight from Datatables "live events" example, should be easy to drop in if you remove the sAjaxsource and go with a plain Datatable..
$('#example').dataTable( {
"bProcessing": true,
"bServerSide": true,
"bJQueryUI": true,
"bStateSave": true,
"sPaginationType": "full_numbers",
"sAjaxSource": " /*your data source page here*/ "
} );
/* Add events */
$("body").on("click", "#example tbody tr", function (e) {
e.preventDefault();
var nTds = $('td', this);
//example to show any cell data can be gathered, I used to get my ID from the first coumn in my final code
var sBrowser = $(nTds[1]).text();
var sGrade = $(nTds[4]).text();
var dialogText="The info cell I need was in (col2) as:"+sBrowser+" and in (col5) as:"+sGrade+"" ;
var targetUrl = $(this).attr("href");
$('#table-dialog').dialog({
buttons: {
"Delete": function() {
window.location.href = targetUrl;
},
"Cancel": function() {
$(this).dialog("close");
}
}
});
//simple dialog example here
$('#table-dialog').text(dialogText ).dialog("open");
});
I am attempting to insert a textarea into a JQuery dialog and I am getting hung up on the syntax of how the dialog I have to work with is set up (I didn't write the dialog by the way, I just want to make changes to it). I have looked at some of the other questions that are similar to this on this site but they don't seem to answer my question so I am hoping someone can shed some light on this for me.
Here is the code:
$('.rejection_toggle').button().click(function(event) {
var $dialog = $('<div />', {
text: Drupal.t('Are you sure you want to reject this form? If so, then please leave a comment as to why you are rejecting it.')
})
var $button = $(this);
$('body').append($dialog);
$dialog.dialog({
title: Drupal.t('Reject this form?'),
buttons: {
'Reject': function (event) {
var $submitID = $button.attr('id').replace('rejection-toggle', 'approval-buttons-reject'),
$submitButton = $('#' + $submitID);
$submitButton.click();
$dialog.dialog('close');
},
'Cancel': function (event) {
$dialog.dialog('close');
}
}
});
return false;
});
So how would I go about inserting a textarea before the buttons?
Thanks.
Ok I figured it out. I need to add:
var textArea = $('<textarea style="width:100%" />');
$dialog.append(textArea);
After the var $dialog line.
Now I need to figure out how to get the input back into Drupal.
By default the jQuery U Autocomplete produces a list of results, upon clicking on a result it will populate the text field with the clicked result text.
I would like to change this behaviour, so that when clicking on a result it will take you to that result's page. To generate the hyperlink I can pass in the ID of the result.
I'm using PHP JSON to bring back the resultset:
$return_arr = array();
while ($row = mysql_fetch_array($fetch, MYSQL_ASSOC)) {
$row_array['id'] = $row['id'];
$row_array['value'] = $row['name'];
array_push($return_arr, $row_array);
}
echo json_encode($return_arr);
And here is my current jQuery:
$(function() {
$("#searchcompany").autocomplete( {
source: "companies.php",
minLength: 2
});
});
Think you need to hook into the select event and supply your own function.
See here for more information.
Supply a callback function to handle the select event as an init option.
$("#searchcompany").autocomplete( {
source: "companies.php",
minLength: 2,
select: function(event,ui) { //Do your code here...
event.preventDefault();
}
});
or Bind to the select event by type: autocompleteselect.
$( "#searchcompany" ).bind( "autocompleteselect", function(event, ui) {
...
});
and to change the matching items to include a hyperlink that can be clicked use the Open event :-
open: function(event, ui) { $( 'li.ui-menu-item a').each( function() {
var el = $(this);
el.attr('href', el.html());
}
); }
This will add an href="[item value]" to each <a> element.
Edit: The code below will allow you to use the open event to change the items to include a href so they show the link in the window and when clicked they will take you to the specified location :-
open: function(event, ui) {
$("ul.ui-autocomplete").unbind("click");
var data = $(this).data("autocomplete");
for(var i=0; i<=data.options.source.length-1;i++)
{
var s = data.options.source[i];
$("li.ui-menu-item a:contains(" + s.value + ")").attr("href", "directory/listing/" + s.id);
}
}
Using this also means that you don't need to use the select event.