Backbone.js with jQuery draggable / droppable. Droppable isn't working - jquery-ui

I have a Backbone app where I am creating 2 views, one draggable, and one droppable. Dragging works ok, but the droppable callback is never fired. How can I get the droppable view to "see" the draggable one?
My "droppable" view:
class App.Views.Folder extends Backbone.View
template: JST['folders/folder']
className: "folder"
initialize: (options) ->
#collection.on('add', #addOne, #)
#collection.on('reset', #addAll, #)
render: ->
#$el.html(#template(#model.toJSON()))
this.$el.droppable(
drop: -> alert("dropped!")
);
Draggable:
class App.Views.QuestionSet extends Backbone.View
template: JST['question_sets/question_set']
className: "question-set"
initialize: (options) ->
#collection.on('add', #addOne, #)
#collection.on('reset', #addAll, #)
#$el.draggable(
handle: ".drag-question-set"
revert: true
)
render: ->
#$el.html(#template(#model.toJSON()))
Update:
The droppable elements fire the callback correctly when I insert the $(draggable.el) into the same container dive as the droppable view. It just doesn't like it when they are in separate html parents...

There's not too much information in your post, but based on your description, if it depends on where in html you put your droppable, you could try replacing your #$el references with just $("#someid") instead. Also, remember that with backbone, the shortcut #$("#someid") is scoped to the backbone view element (some sub element of the global document set in the constructor), not the global document itself. Assuming you get the $("#someid") parts to work, it's most probably just a scoping issue.

I figured it out... Turns out it was a "tolerance" issue with the Droppable plugin. Setting {tolerance: "pointer"} solved my issue.

Related

Backbone Marionette onDomRefresh jquery-ui click multiple firing

I have defined a Marionette View, and I need to reflect the model change event. I have my initialize function like so:
initialize: function(){
_.bindAll(this,"render");
this.model.on('change',this.render);
},
Later, I have defined my jquery-ui element initializers in onDomRefresh method. It is a draggable and resizable element, which can be writeable when you click on it. When clicking outside the element, the text is saved.
onDomRefresh: function(){
var self = this;
if(this.$el.resizable()){
this.$el.resizable('destroy');
}
this.$el.resizable({ handles: "n, e, s, w, se, sw, nw, ne" });
this.$el.on('resize', function (e) {
e.stopPropagation();
});
this.$el.draggable().click(function(e){
$(".selected").removeClass("selected");
$(this).addClass("selected");
$(this).draggable( "option", "disabled", true );
$(this).attr('contenteditable','true');
$(this).css({cursor:'text'});
$(this).css({opacity:'100'});
}).blur(function(){
$(this).draggable( 'option', 'disabled', false);
$(this).attr('contenteditable','false');
$(this).css({cursor:'move'});
self.textchange(); //update and save the text in the model
});
}
The problem comes, when the model has nested some model change events, and the click function is firing more and more times. I have been looking for jquery click event solutions, and none of them seems to work for me.
Tried solutions:
this.$el.draggable().unbind("click").click(function(e){});
this.$el.draggable().off("click").on('click',function(e){});
this.$el.draggable().one('click', function(e){});
//with jquery sparkle
this.$el.draggable().once('click', function(e){});
I also notice that sometimes onDomRefresh method fires two times. Don't know how to fix that. Any ideas are more than welcomed.
I have added this call at the beggining of onDomRefresh() function, which unbinds all the events on the element:
this.$el.unbind();
Now, the click event fires just once after rerendering the view.

Why do I lose draggable after drag?

I just migrated to backbone and have a strange behaviour.
I attach draggable to an element which is created by a script, thus not directly available in DOM.
EDIT:
The element that is created is .nav, $("#viewer") as container is already in the DOM.
In plain jQuery i used .on and mousemove event for this and it worked.
With backbone I use the same in the initialize method:
initialize: function(options) {
this.viewer = $("#viewer");
this.viewer.on("mousemove", '.nav', function() {
$(this).draggable();
});
This seems to work, but only one time.
After dragging the element one time, I can't drag it anymore.
Are there conflicts with the events? Am I missing something?
You have to refer to $('#viewer') after you've called render(). initialize is called before render, and so the DOM element doesn't exist.
Also, use this.$('#viewer'), and it will grab the element (after render) even if it hasn't been appended to your page's DOM.
myView = new ExampleView({ model: myModel });
$(body).append(myView.render().el);
myView.onRender();
// -------------
// Now on your view:
onRender: function() {
this.viewer = this.$('#viewer');
this.viewer.on("mousemove", '.nav', function() {
$(this).draggable();
});
},
UPDATE
You can also, to make such things simpler, customize Backbone to automatically call the onRender() function after rendering, by triggering an event or something.
Marionette.js (a Backbone.js extension) has this built in and I use it all the time.
The solution finally was pretty easy:
make sure you dont use outdated versions of backbone.js and underscore!!
After i updated the versions to latest I made it work with:
render: function() {
this.viewer.on("mouseover", '.nav', function() {
if (!$(this).data("init")) {
$(this).data("init", true);
$(this).draggable();
}
});
Probably still not very elegant but i couldnt made the suggested onRender method from dc2 work.

Controling height in jQuery UI Accordion with dynamic data

I'm using an jQuery accordion control with knockout to dynamically add/remove items to the control based on some client-side activity. I've created a knockout binding like such:
ko.bindingHandlers.accordion = {
init: function (element, valueAccessor) {
var options = valueAccessor() || {};
setTimeout(function () {
$(element).accordion(options);
}, 0);
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).accordion("destroy");
});
},
update: function (element, valueAccessor) {
var options = valueAccessor() || {};
$(element).accordion("destroy").accordion(options);
}
}
Now my problem is the sizing of the accordion... it always looks very compressed (vertically). I've tried setting the height of the DIV that contains the control, like this:
<div id="LearningPaths" data-bind="foreach: allLearningPaths, accordion: {}" style="height:500px; border:1px solid red;">
But the panels in the accordion don't change... they still aren't very "tall". Here's what it looks like: http://sdrv.ms/STA9Y6
I think there's a setting I can pass in when I use the .accordion(), but with my binding handler I'm not sure how to do that as I'm already passing in the 'options' object.
What I want is to have the content area of each panel to expand to the entire available side in the accordion control... ideas?
First i think your problem is someone related to SharePoint web parts. I created a accordion solution which is based on the summary link web part in SharePoint and can be found here: http://www.n8d.at/blog/turn-summary-link-web-part-into-an-accordion/
I wrote my own accordion to accomplish this, which also makes sure that if you like to edit the page the accordion script won't be loaded.
On the other hand i think your problem is more related to css and not to jquery. Do you use float style in your css? Then you need to make sure that you use the so called clear-fix.
This can be done in define the following style:
.panel:after{
clear: both;
}

Ember.js + jQuery UI Draggable Clone

I am trying to use Ember.js in conjunction with jQuery UI's draggable functionality, but I am encountering problems. Specifically, when using the clone helper, I am not able to drop the element and everything is extremely laggy. If I don't use the clone helper, everything works as expected.
I suspect this is related to jQuery UI cloning the html, including all of the metamorph script tags (used for binding).
I don't need to update the element live while I am dragging it. Is there a way to strip binding tags with ember?
For reference, here is the view logic:
didInsertElement: ->
#_super()
#$().draggable
cursor: 'hand'
helper: 'clone'
opacity: 0.75
scope: #draggableScope
#$().droppable
activeClass: 'dropActive'
hoverClass: 'dropHover'
drop: #createMatch
scope: #droppableScope
My first thought was to try and use a beginPropertyChanges and endPropertyChanges during the drag to prevent an unexpected behavior. This doesn't seem to work nor is it ideal as I would like other bindings to update. Here is the revised code where I attempted this:
didInsertElement: ->
#_super()
#$().draggable
cursor: 'hand'
helper: 'clone'
opacity: 0.75
scope: #draggableScope
start: ->
Ember.beginPropertyChanges()
stop: ->
Ember.endPropertyChanges()
#$().droppable
activeClass: 'dropActive'
hoverClass: 'dropHover'
drop: #createMatch
scope: #droppableScope
Any help would be greatly appreciated.
I got this working by stripping all ember related metadata manually. Here is a small jquery plugin I whipped up:
# Small extension to create a clone of the element without
# metamorph binding tags and ember metadata
$.fn.extend
safeClone: ->
clone = $(#).clone()
# remove content bindings
clone.find('script[id^=metamorph]').remove()
# remove attr bindings
clone.find('*').each ->
$this = $(#)
$.each $this[0].attributes, (index, attr) ->
return if attr.name.indexOf('data-bindattr') == -1
$this.removeAttr(attr.name)
# remove ember IDs
clone.find('[id^=ember]').removeAttr('id')
clone
To get it to work, just set the helper as follow:
helper: ->
$this.safeClone()
I was having the same issue using Ember 1.0.0 RC6. I've found that just replacing the clone string with a function which returns the clone works fine.
this.$().draggable({
// helper: 'clone'
helper: function() {
return $(this).clone();
}
});
In Coffeescript
#$().draggable
# helper: 'clone'
helper: ->
$(#).clone()

jQuery Drag and Drop Breaks When Loading Divs by AJAX

I have a list of draggables that need to be dropped onto divs loaded by AJAX. However, when the divs are loaded by AJAX it breaks the droppables functionality. I removed AJAX from the equation and it worked fine.
Here's working code. With this code I can drag items in my .contentList to #block1 div and everything works peachy.
<div id="block1"></div>
$(".contentList").draggable();
var dropOpts = {
hoverClass: "activated",
tolerance: "pointer",
drop: getURL
};
$("#block1").droppable(dropOpts);
I then have the following code load a new div via jQuery .load.
$(document).ready(function() {
$("#template1").click(function() {
$("#dynamic-ui").load("/templates/newtemplate.html");
});
The newtemplate.html contains a div with the same id; #block1. However, once it loads I can no longer drag onto it. Any help would be greatly appreciated!
Add the code to make #block1 droppable after the newtemplate.html is loaded into dom. e.g.
$(document).ready(function() {
$("#template1").click(function() {
$("#dynamic-ui").load("/templates/newtemplate.html");
var dropOpts = {
hoverClass: "activated",
tolerance: "pointer",
drop: getURL
};
$("#block1").droppable(dropOpts);
});
});
The binding of events happens when the browser loads the webpage.
So during the loading if the JavaScript didn't find the specified division/element they won't bind the event. So for dynamically created divisions you need use jQuery live to bind the events.
For your question i think this question will answer you.
Hope it will help you.
Good luck

Resources