Ember.js + jQuery UI Draggable Clone - jquery-ui

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()

Related

jquery-ui drag and drop across multiple divs with sort

I'm trying to create a jquery drag and drop solution and am a little lost with how I achieve the following.
Allow '.todo-task' to be dropped into any of the 4 'backlog, pending, inProgress, completed' div containers.
Use a highlight helper to show where the task will be placed in the container.
Be able to drag and drop with in a container to change to order.
my first issue is that I cannot seem to be able to activate the drag items correctly.
I have created a jsfiddle with the code I have so far. Appreciate any guidance / help
here is my jquery code
$(".task-container").contents().find(".todo-task").draggable({
connectToSortable: ".ui-droppable",
helper: function (event) {
},
iframeFix: true,
// stop: makeSortable()
stop: function (event, ui) {
// alert('stop');
}
});
$(".ui-droppable").sortable({
placeholder: "ui-state-highlight",
opacity: .5,
//dropOnEmpty: true,
helper: 'original',
beforeStop: function (event, ui) {
newItem = ui.item;
},
receive: function (event, ui) {
},
}).disableSelection().droppable({
over: ".ui-droppable",
activeClass: 'highlight',
drop: function (event, ui) {
$(this).addClass("ui-state-highlight");
}
})
I'm not sure exactly what else you're trying to achieve in terms of the "disabled" style CSS, but I just forked and monkeyed around with this for a minute:
jsfiddle
One thing is that I think your jQuery methods are redundant. Why say:
$(".task-container").contents().find(".todo-task").draggable( ...etc.
When you can just as easily do this:
$(".todo-task").draggable( ...etc.
So I cleaned a little bit of that up.
The other thing I did was to make the .task-container droppable.
See the jQuery API: droppable methods
This allows you to sort and move between columns, but like I mentioned this fix seems to behave strangely with your CSS class methods.

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.

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

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.

Backbone Views defined in Head not working unless using Routes

I'm using the "rails-backbone" gem in my Rails 3.2 project. By this design my Backbone Views are loaded in the <head> tag. When using Routes everything works fine, but Views do not render if I try to use them directly without Routes. If I put the Views code in <body> everything works as expected.
Is there a way to make the Views work when defined in <head>?
Update:
in <body>:
<script type="text/javascript">
var lv = new ListView();
</script>
in javascript file included in <head>:
window.ListView = Backbone.View.extend({
el: $("#node"), // This does not work
initialize: function(){
_.bindAll(this, 'render');
this.el = $("#node"); // Works if I add this line
this.render();
},
render: function(){
$(this.el).append("<ul> <li>hello world</li> </ul>");
}
});
As I understand it #node does not exist yet, which is why it is not bound to el. I don't quite understands when happens here: var lv = new ListView(), I thought I was creating an instance from a Class (I guess I'm getting a clone of an Object?). Is there another way of making the code work by modifying the code in <body> instead of the included javascript?
Your problem is caused by using a jQuery selector as the value for el in the view.
Read this:
http://lostechies.com/derickbailey/2011/11/09/backbone-js-object-literals-views-events-jquery-and-el/
if you want something to work in the head, but after the DOM is ready, (And apparently since you're using jQuery) just set up your views in the DOMReady event via:
$(document).ready(function(){
...
//set up view here
...
});

Rails 3.1 Backbone JST in View will not compile with events

Working with the rails 3.1 asset pipeline and coffeescript.
I've used the rails-backbone gem for some generation to help me along and everything has been working well for me until I tried to put events to my view. As soon as I put anything to the events attribute the JST does not render (it does without it):
Headspace.Views.Shows ||= {}
class Headspace.Views.Shows.IndexView extends Backbone.View
template: JST["backbone/templates/shows/index"]
el: '#show_listing'
initialize: () ->
#collection = #options.collection
this.render()
events:
'click .show_header' : 'show_details'
show_details = ()->
alert('action')
render: ->
$(#el).html(#template({collection:#collection}))
I've also tried an empty events attribute (which doesn't compile unless I put in the empty {}) which does render the JST. I've considered that el is defined as a string instead of a jQuery element (with $()) until the render function. If I do specify:
el: $('#show_listing')
and:
render: ->
el.html(#template({collection:#collection}))
The JST does not compile.
just a mere typo you got there
instead of
show_details = ()->
alert('action')
it is
show_details : ()->
alert('action')
I am guessing you used shift+enter in textmate for the functions snippet? I have done that, too.

Resources