Drag and drop in Monaca and Onsen



  • Hi all

    What’s the best way to create a very simple drag and drop application with Monaca and Onsen please?

    I don’t seem to be able to get JQuery UI to do anything and angular directives like angular-dragdrop seem to do nothing. I don’t get any errors, they just don’t seem to do anything.

    I was wondering if I could use hammer.js which I believe is part of onsen, but I couldn’t get that working either.

    I don’t have specific code to post I’m afraid because it’s gone in so many circles today and I’ve no particular approach I favour currently.

    Totally stuck and feeling like a complete newbie, so any ideas thankfully received.

    Thanks all!

    Dougi



  • Since this post I have now managed to get dragging working with JQuery UI in the browser. It still fails on the mobile device though. I have jQuery UI Touch Punch installed, but it doesn’t seem to be working. Will try further tomorrow, but in the mean time if anyone has any pointers for this it would be greatly appreciated.

    Thanks!



  • I’ve cracked it!! It was just a question of using the right version of touch-punch. So for anyone who needs to do this my steps were:

    • add component jquery-ui (which also adds jquery) making sure to include “core”, “widget”, “mouse”, “position”, “draggable” and “droppable”.
    • add component jquery-ui-touch-punch

    Index.html

    <!DOCTYPE HTML>
    <html ng-app="myApp">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        <script src="components/loader.js"></script>
        <script src="js/winstore-jscompat.js"></script>
        <link rel="stylesheet" href="components/monaca-onsenui/js/angular/angular-csp.css">
        <link rel="stylesheet" href="components/loader.css">
        <link rel="stylesheet" href="css/style.css">
    
    
        <script>
            var module = angular.module('myApp', ['onsen']);
    
            module.controller("AppController", function ($scope) {
                
            }).run(function ($rootScope) {
    
            });
    
        </script>
        
        <script src="js/Page1Controller.js"></script>
        
    </head>
    <body>
        <ons-navigator var="myNavigator" page="page1.html">
        </ons-navigator>
    </body>
    </html>
    

    Page1.js controller

    module.controller("Page1Controller", function ($scope, $rootScope) {
        ons.ready(function () {
            $("#draggable" ).draggable();
        });
    })
    

    Page1.html

    <ons-page ng-controller="Page1Controller">
        <ons-toolbar>
            <div class="center">Navigator</div>
        </ons-toolbar>
    
       <div class="item" id="draggable">dragger</div>
    
    </ons-page>
    
    

    Style.css

    .item{
        width:100px;
        height:100px;
        background-color:rebeccapurple;
    }
    

  • Onsen UI

    @DougiUK Thanks for sharing! About AngularJS directives, they should work if you include them in ons.bootstrap or in angular.module('myApp', ['onsen']) after “onsen”.



  • @Fran-Diox

    Thanks. Yes, I think I was just a bit confused by the way that the loader.js file adds dependencies for me. It’s good now that I’ve sussed it :)

    Great product thanks.



  • I think I may have come across another “interesting” one, and I’d welcome advice please.

    I have just added a sliding menu to the project with the drag and drop element in it. It worked perfectly just before adding the sliding menu, but it now fails.

    I inspected the HTML in Chrome and it seems that the sliding menu is creating two elements in the dom called “ons-sliding-menu-inner”. The first contains the menu ons-page elements and the second contains the ons-page that gets loaded into the main window by the sliding menu.

    It seems that these “ons-sliding-menu-inner” elements have touch events associated with them that are preventing the dragging of the child element that I have set up and which works if the sliding menu isn’t used (which probably explains why I was going in circles yesterday).

    I note that there is a “swipeable” attribute, and although setting this to false does prevent the swiping it doesn’t allow the touch events to bubble down to the dragging element.

    I also tried setting the “swipe-target-width”, and although setting this to 20px did make only the first 20px from the left side sensitive to the swipe, the rest of the screen area was still not bubbling down to the draggable element.

    I tried all three “type” settings for the menu in case they worked differently, but that made no difference.

    So the question is…Is there a way to combine the sliding menu with draggable on-screen content?

    The only difference to the code posted up the page here is the addition of the sliding menu on the index.html page (replacing the ons-navigator) as follows:

    <ons-sliding-menu var="module.slidingMenu" menu-page="menu_main.html" main-page="page1.html" side="left" type="reveal">
    </ons-sliding-menu>
    

    Thanks in advance!



  • OK, so I’ve now isolated the sliding menu touch events that are preventing my draggable element from dragging.

    By setting swipeable=“false” on the sliding menu it reduces the problem touch events to just two.

    Firebug lists them as:

    div.onsen-sliding-menu__main.ons-sliding-menu-inner - the touch event is “dragstart”

    and

    ons-sliding-menu.ng-scope - the touch event is “dragstart” here too

    0_1456156112793_onsen.JPG

    Disabling these event listeners in Firebug makes my draggable element work perfectly and menu access is just done by clicking on the “bars” icon I have in my topbar which triggers module.slidingMenu.toggleMenu() which means it all works perfectly.

    So the question is, how do I disable the event listeners for these elements in code? I assume in ons.ready in the angular controller for the page, but what would the syntax be please?

    Thanks in advance.



  • @DougiUK Odd thought, but for all the reworking of the framework you are doing for just the sliding menu, would a better navigation scheme benefit your project or would a different menu system help?

    I mean, keep up the great work, because I have been learning a lot from your trials, but now it seems like you are reworking / rewriting the framework when I wonder if you could avoid it by using another method for nav?

    As far as suggestions, the only things I can come up with would be to try to cancel the event before it bubbles, i.e. event.cancelBubble=true or try to identify and remove the eventListeners, i.e. target.removeEventListener(type, listener[, useCapture])



  • @munsterlander Thanks for the suggestions, much appreciated. I’ll take a look at these.

    I agree that if I am stuck on this for much longer then a different navigation pattern is going to have to be adopted. Most likely the <ons-tabbar> because I don’t expect that to have the same issues.

    It would just seem a pity because the sliding menu is ideal for what I need (I have a fair few menu options which are wordy and at the same level).

    Thanks very much for your feedback :smile:


  • Onsen UI

    @DougiUK I’m not sure why that happens. If you combine sliding menu with a carousel both of them can take the click. I just made a codepen for another issue where you can see it: http://codepen.io/frankdiox/pen/YqKOJE
    Perhaps you can figure out something from that :/



  • @Fran-Diox Thanks Fran, much appreciated. Interesting that your example here works. I’ll take a bit more of a look.

    In the mean time I have dropped the sliding menu in favour of topbar buttons with popover. This works fine for now.

    Thanks for your support and for a great product :)



  • OK, so I’m starting to go a little bit crazy now. Something that should be so simple is proving really hard to achieve. I’ve dumped the sliding menu and am now just using a totally clean and empty app structure so that I can get the drag and drop working in basic form. I realised that the drag and drop that I managed to get working was just a jquery version and so wouldn’t bind to ng-repeat etc in the views. So I have to find an angular version.

    I have managed to get http://codef0rmer.github.io/angular-dragdrop/#/ working locally perfectly in a basic html site (not a monaca project). The local project is a single file with angular-dragdrop.min.js reference as follows:

    Index.html

    <!DOCTYPE html>
    <html ng-app="MyApp">
    <head lang="en">
    
        <meta charset="utf-8">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
        <script src="angular-dragdrop.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.0/ui-bootstrap-tpls.js"></script>
        
        <script>
            var App = angular.module('MyApp', ['ngDragDrop', 'ui.bootstrap']);
            App.controller('myController', function ($scope, $q) {
            });
        </script>
        
    </head>
    <body>
        <h2>Dragging test</h2>
        <div ng-controller="myController">
            <div class="btn btn-primary" data-drag="true" jqyoui-draggable="{animate: true}" style="background-color:rebeccapurple; padding:20px; width:100px;">DRAG ME!!!</div>
        </div>
    </body>
    </html>
    
    

    So I then went to try and replicate this in monaca, but I don’t seem to be able to. I have the following JS components installed in my build config:

    0_1456729635549_installedComponents.JPG

    …which seems to cover things. I find the way that the JS components are installed confusing though because you have to select all the files to be loaded for each of the components.

    The following is the code that I have in my monaca app now. I believe this should be working in the browser. I guess I’d need touch-punch for mobile support, but for now, one thing at a time.

    <!DOCTYPE HTML>
    <html ng-app="MyApp">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        <script src="components/loader.js"></script>
        <link rel="stylesheet" href="components/loader.css">
        
         <script>
         
            var myApp = angular.module("MyApp", [
                'onsen',
            ]);
            
            myApp.controller('MyController',function($scope){
                
            });
            
        </script>
        
    </head>
    <body>
    
        <h2>Dragging test</h2>
        
        <div ng-controller="MyController">
            <div class="btn btn-primary" data-drag="true" jqyoui-draggable="{animate: true}" style="background-color:rebeccapurple; padding:20px; width:100px;">DRAG ME!!!</div>
        </div>
        
    </body>
    </html>
    

    No errors display in the Firebug console. It just fails silently.

    Does anyone have any idea why this wouldn’t be working please?

    Does it matter in what order I add the components by the way? It seems that if you add jquery after other things that depend on it then it shows as a reference error saying “Jquery is not defined”. If so, is it possible to re-order the components to avoid having to go through the time consuming installation process (the interface is slow) over again? Or at least is there a way to select all files when adding a component? That way I could select all and then deselect the few that aren’t required.

    Or is there a way to download and include the the files that are in my offline version and include them in the loading sequence within monaca to ensure that the components being loaded are the same as my local test?

    Basically, ANYTHING that will get this working.

    Thanks in advance!

    ps - if anyone fancies quoting me for creating a working version of this I would consider paying. Draggable elements would need to be able to be bound to an ng-repeat and drop events triggered as per the angular-dragdrop plugin. Thanks.



  • I think I’ve sorted it!

    I just hadn’t resolved the dependency “ngDragDrop” in the main module of the application:

    var myApp = angular.module("MyApp", [
      'onsen',
      'ngDragDrop', /*this was missing*/
    ]);
    

    Total schoolboy error, but I was getting confused by the way that the loader works in Monaca.

    So, for anyone else having problems with the loader and js components, remember that you need to add the dependency as above, just like for any angularjs app. This still doesn’t explain the sliding menu thing of course, but at least it explains the drag and drop failing.

    Hope this may help others and happy coding!


Log in to reply