For a jquery-ui dialog inside a render function, can I have buttons that point to another function and not inline it?
var MyView = Backbone.View.extend({
submit: function(event) { /* foo */ },
buttons: [{
'text' : 'SUBMIT',
'click' : this.submit // <== like this
}],
render: function() {
this.$el.append("I'm a dialog with a button").dialog({ buttons: this.buttons });
return this;
}
});
I ran the above code as is, and it seems like the engine can't find submit:
Uncaught TypeError: Cannot call method 'apply' of undefined jquery-ui.js:10018
$.widget._createButtons.$.each.props.click jquery-ui.js:10018
jQuery.event.dispatch jquery-1.9.1.js:3074
jQuery.event.add.elemData.handle jquery-1.9.1.js:2750
The buttons array is interpreted when you declare your view and at that point this is set to the root object (probably window). You can demonstrate this behavior by assigning something to window.submit. For example,
window.submit = function() {
console.log('window submit');
}
is triggered when you click on your button. See http://jsfiddle.net/nikoshr/AmRkp/ for a demo.
A solution to your problem would be to use your definition as a template to build a custom array of buttons for each instance. Something like this :
var MyView = Backbone.View.extend({
submit: function(event) {
console.log(this, 'submit');
},
buttons: [{
'text' : 'SUBMIT',
'click' : 'submit'
}],
render: function() {
var mybuttons;
//extract the buttons from an array or function,
mybuttons = _.result(this, 'buttons');
//build the array
mybuttons = _.map(mybuttons, function(obj) {
// for each object describing a button
//create a clone to avoid problems
obj = _.clone(obj);
//set the callback, bound to the view
obj.click = _.bind(this[obj.click], this);
return obj;
}, this);
this.$el.append("I'm a dialog with a button").dialog({
buttons: mybuttons
});
return this;
}
});
See http://jsfiddle.net/nikoshr/AmRkp/3/ to play with
Related
I'm a bit of a novice when it comes to React, so hopefully someone can help.
I've been able to create a generic view switching component using React.
var ViewSwitcherContainer = React.createClass({
getInitialState: function() {
return {
activeViewName : this.props.views[0].Name
};
},
selectView: function(name) {
this.state.activeViewName = name;
this.forceUpdate();
},
render: function () {
return <div>
<ViewSwitcher views={this.props.views} onViewSelection={this.selectView}/>
<ViewSwitcherContent views={this.props.views} activeViewName={this.state.activeViewName}/>
</div>;
}
});
Here is a JSFiddle demonstration...
http://jsfiddle.net/paheal/j8Ubc/
However when I try to load that switching component in a modal component I sometimes get an'Uncaught Error: Invariant Violation: findComponentRoot(..., .r[3iziq].[1].[0].[1]): Unable to find element. This probably means the DOM was unexpectedly mutated (e.g. by the browser).' error from react.
var ModalView = React.createClass({
getInitialState: function () {
this.viewDefinitions = [
{DisplayName:'View A', Name:'viewA', View:ViewA},
{DisplayName:'View B', Name:'viewB', View:ViewB}
];
return {};
},
componentDidMount: function () {
$("#" + this.props.modalId ).dialog({
autoOpen: false,
height: 400,
width: 400,
modal: true,
draggable: false,
resizable: false
});
},
render: function () {
return <div id={this.props.modalId} title={this.props.modalId}>
<ViewSwitcherContainer views={this.viewDefinitions}/>
</div>;
}
});
Here is a JSFiddle demonstration...
http://jsfiddle.net/paheal/j8Ubc/7/
What am I missing? Is the problem in my modal component or in the view switching components?
I actually worked out what was wrong. It seems that the dialog functionality in jQueryUI adds to the DOM, by dynamically creating div for the dialog and its title bar.
Depending on the timing of things, that can cause issues when React is doing its reconciliation.
To resolve I implemented a Reactified version of a modal dialog.
I'm trying to dynamically add a menu item to my HighChart to support dynamic drilldowns with a function name that is dynamically generated. I'm able to successfully add new menuItems to the existing contextButton when using statically defined functions like alerts, however, when I have a function defined using a var it won't invoke the proper function.
the following is working:
var chartOptions = {
chart: {
renderTo: myChartDiv,
zoomType: 'x',
type: 'area'
},
exporting: {
enabled: true,
buttons: {
contextButton: {
menuItems: [{
text: 'My Test',
onclick: function() {
alert('success!');
}
}]
}}
}};
However, as soon as I want to add a new menu item with a function defined in a variable, the call defined by the variable is skipped. ie:
var c1 = "chart1";
var c2 = "chart2";
var drilldownMethod = "toggleCharts('" + c1 + "','" + c2 + "')";
var newDrilldown = {
text: Show Chart 2,
onclick: function () {alert('test1'); drilldownMethod; alert('test2') }
};
chartOptions.exporting.buttons.contextButton.menuItems.push(newDrilldown);
I do see the new menu item "Show Chart 2", and when I click it, I do get the alerts 'test1' and 'test2' appear; however, the function in the string variable "drilldownMethod" is never invoked (there's an alert in that method as well to prove the point).
Any thoughts on how to accomplish this?
drilldownMethod is a string, not a function call, that's why you don't see it executing. This should work:
chartOptions.exporting.buttons.contextButton.menuItems.push({
text: 'Show Chart 2',
onclick: function () {
toggleCharts("chart1", "chart2");
}
});
I'm trying to get some animation to work during a Backbone View's render operation that is called when I have refreshed the data of the underlying model to a new record.
SiteView = Backbone.View.extend({
initialize: function () {
this.model.bind('change', this.render, this);
},
render: function () {
if (this.model.get('name')) {
var callback = function (view) {
view.$("#activesite_name").empty().append(view.model.get('name'));
view.$("#activesite_desc").empty().append(view.model.get('description'));
$(view.el).show('drop', { direction: 'down' }, 'slow').removeClass('hidden');
};
$(this.el).filter(':visible').fadeOut(500, callback(this));
}
}
});
However, the jQuery UI callback function is being executed before the show operation is, resulting in the UI updating and then disappearing when refreshing from one model selection to another.
How can I get the callback to be called only once the element is properly hidden?
Try this:
render: function () {
if (this.model.get('name')) {
var view = this;
var callback = function () {
view.$("#activesite_name").empty().append(view.model.get('name'));
view.$("#activesite_desc").empty().append(view.model.get('description'));
view.$el.show('drop', { direction: 'down' }, 'slow').removeClass('hidden');
};
$(this.el).filter(':visible').fadeOut(500, callback);
}
}
Using jquery-ui to create a dialog is pretty easy:
<script>
$(function() {
$( "#dialog" ).dialog();
});
</script>
<div id="dialog" title="Basic dialog">
<p>This is the default dialog which is useful for displaying information. The dialog window can be moved, resized and closed with the 'x' icon.</p>
</div>
...but one still needs a div in the HTML for this to work. In Dojo:
var dlg = new dijit.Dialog({
title:"dialog",
style: "width:30%;height:300px;"
});
dlg.show();
would just do the trick without anything specified in the html section, can jquery-ui do this? (I have to use jquery-ui here)
Thanks,
David
While I'm not sure why you would want to open a dialog with no content, you could easily create a new one on the fly and invoke the jquery dialog against it:
$("<div>hello!</div>").dialog();
basic code
var d = $("#someId");
if (d.length < 1)
d = $("<div/>").attr("id", "someId")
.appendTo("body");
else
d.dialog('destroy');
d.html('some message')
.dialog({ some_options })
.dialog("open");
and you can probably put rap this in an extension method.
Update (my full code listing)
(function($) {
$.extend({
showPageDialog: function (title, content, buttons, options) {
/// <summary>Utility to show a dialog on the page. buttons and options are optional.</summary>
/// <param name="buttons" type="Object">Dialog buttons. Optional, defaults to single OK button.</param>
/// <param name="options" type="Object">Additional jQuery dialog options. Optional.</param>
if (!buttons)
buttons = { "Ok": function () { $(this).dialog("close"); } };
var defOptions = {
autoOpen: false,
modal: true,
//show: "blind",
//hide: "explode",
title: title,
buttons: buttons
};
if (options)
defOptions = $.extend(defOptions, options);
var pd = $("#pageDialog");
if (pd.length < 1)
pd = $("<div/>").attr("id", "pageDialog")
.appendTo("body");
else
pd.dialog('destroy');
pd.html(content)
.dialog(defOptions)
.dialog("open");
}
}//end of function show...
)//end of extend Argument
})(jQuery)
Sample Usage
$.showPageDialog(title, message, {
"Yes": function () {
$(this).dialog("close");
// do something for 'yes'
},
"No": function () {
// do something for no
}
}
var div = document.createElement('div');
div.innerHTML = "Hello World";
$(div).dialog();
Juan Ayalas solution should work for modal Dialogs.
For a non modal dialog it would be better to track the id inside the function.
I use the following code which is not perfect but should work to ensure that the
id is unique. The code is nearly equal to Juan Ayalas example but uses a counter to avoid a duplicate id. (Furthermore I deleted the OK-Button as default).
(function($)
{
var dCounter=0; //local but "static" var
$.extend({
showPageDialog: function (title, content, buttons, options) {
/// <summary>Utility to show a dialog on the page. buttons and options are optional.</summary>
/// <param name="buttons" type="Object">Dialog buttons. Optional, defaults to nothing (single OK button).</param>
/// <param name="options" type="Object">Additional jQuery dialog options. Optional.</param>
if (!buttons)
buttons = {}; //{ "Ok": function () { $(this).dialog("close"); } };
var defOptions = {
autoOpen: false,
width: "auto",
modal: false,
//show: "blind",
//hide: "explode",
title: title,
buttons: buttons
};
if (options)
defOptions = $.extend(defOptions, options);
dCounter++;
//console.log("dCounter is " + dCounter);
var pdId = "#pageDialog"+dCounter;
var pd = $(pdId);
if (pd.length < 1)
pd = $("<div/>").attr("id", pdId)
.appendTo("body");
else
pd.dialog('destroy');
pd.html(content)
.dialog(defOptions)
.dialog("open");
}//end of function showPageDialog
}//end of extend options
)//end of extend argument
}//end of function definition
In my extension where the overlay.js comprises of the following events:
var sto =
{
onLoad: function() {...},
onMenuItemCommand: function(e) {...},
onToolbarButtonCommand: function(e) {...},
};
window.addEventListener("load", function () { sto.onLoad(); }, false);
I would need a listener fired every time a button is clicked in a loaded page. How can I achieve this?
Well I'm not sure if that's what u want but u can try to do an event delegation on the entire document:
var document_mouseup_lst = EventListener.createEventListener();
doc.addEventListener("mouseup", document_mouseup_lst, false);
document_mouseup_lst.addEvent("mouseup", function click(e, callback, object){
var element = e.target;
if(element.tagName.toLowerCase() === 'button') {
if (e.which == 1) { // left click
// do whatever u want
} else if (e.which == 2) { // middle click
// do whatever u want
}
}
return false;
});
btw in order to create the eventlistener (the EventListener object which got the createEventlistener method) I used this page Ajaxian >> An alternative way to addEventListener
I found the solution - was quite easy. Ok here is the source:
https://developer.mozilla.org/en/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
and the modified code:
var sto =
{
onLoad: function() {...},
onMenuItemCommand: function(e) {...},
onMouseClick: function(e) {...},
onToolbarButtonCommand: function(e) {...},
};
window.addEventListener("load", function () { sto.onLoad(); }, false);
document.addEventListener("click", function(e) { sto.onMouseClick(e); }, false, true);