Sunday, January 24, 2016

Angular Multiple ng-transclude

Quick post that may save someone a lot of time and frustration. Transclusion is a great feature in Angular (see the documentation). The ability to use multiple ng-transclude bits in your template makes it even greater. However, it took me a long time to get the simplest example to work. The problem was that each occurrence of ng-transclude in my template, even though assigned to a specific slot, did end up including everything from the HTML and not just the specified slot.

I compared my work to other examples that did work and found no difference at all in the template, the HTML, nor the code.

Long story short, I noticed in some article on the subject that the multiple transclusion feature was added to Angular starting 1.5. I went to check my bower.json and indeed, I was on angular 1.4.8. Upping the version to 1.5 did solve the problem.

Thursday, January 7, 2016

Android: From Java to JavaScript and Back


After the fight with Android Studio and Eclipse yesterday, I finally got to try what I was planning to do all day:

  • From within JavaScript running in a WebView, Invoke Android Java code , and  
  • From Android Java code, inject JavaScript code into an HTML page in a WebView. 

There are a few samples that can be found for both routes, either in the official docs or in blog posts. However, there were some tricks to get even the simplest example running.

Other than the standard issues of having to enable JavaScript in the WebView and annotate the callback method, here are a couple of interesting ones that I faced trying the first route:

  • Default WebViewClient: Attempted to run some trivial JavaScript inside the WebView to make sure it is enabled. The simplest of examples (popping an alert) did not work. After looking around, it turns out that you must set a WebViewClient on the WebView, even if it is simply the default one from the SDK. Apparently, it provides a method that handles showing alerts to make them fit with the theme, etc.
  • Method Signature: The simplest of examples for calling Java from JavaScript did not work for me. I was getting a "Error calling method on NPObject" message. After trying a couple of things I decided to post on StackOverflow, but I had to double check my code before doing so. And guess what I found? I found that the method signature called from JavaScript did not match the one declared in Java. Fixing that got the sample to work.

The second route was not a smooth ride either. Here are a few issues I encountered:


  • Threading: Apparently, any interaction with a WebView has to happen on the 'same' thread (as the error stated). I figured that this meant the event thread, and indeed scheduling the injection of JavaScript using runOnUiThread solved this.
  • Navigation: Upon successful execution of JavaScript code, the original page content was replaced by the result of the JavaScript statement that just executed. Apparently, this is to be expected and others have solved this by appending a void(0); to the JavaScript code. The reason is explained here in detail.
  • Arguments: When passing JavaScript code as a String do not forget to quote values that are supposed to be String valued. This simple advice might save you considerable time if you are passing around element IDs. Apparently, when an element ID appeared in the JavaScript unquoted the interpreter took at it as a reference to the element!


Wednesday, January 6, 2016

Android Studio and ADT on Ubuntu

This was not a fun day.

I spent hours trying to set up Android Studio on Ubuntu. I followed the instructions given here (after eliminating the extra spaces in the URL) and things seemed to be going. After the install, I went through some gyrations to get the Studio to update and run. I imported a project and tried to run it and the IDE started throwing exceptions in the logs. I fought with it a bit, trying to update the SDK, tools, and installing the missing 32-bit C libraries as suggested in this post (only a few are actually needed, it seems, but I installed all just in case). However, new errors kept popping up and I finally decided to go back to what I know; the Android Eclipse plugin.

It was a surprise to me that Google removed the installation instructions for the Eclipse plugin from their site in an attempt to push the Android Studio. And indeed they tout it as the official IDE now and urge people to migrate.

Anyways, I got the plugin from the Eclipse Marketplace. After installing the SDK (again) and trying to run a sample, Eclipse complained about inability to connect to adb, and kept retrying. I went ahead and manually started the adb server from the command line and this did work, at least the first time. Thereafter, Eclipse complained that the connection was lost and prompted me to start both adb as well as Eclipse itself! After having to do this a couple of times, I realized that the SDK path pointed to the first one I installed, which did seem to be broken in some way. Fixing the path got things working again.

Next, I went back to my project but it had compile errors. Apparently, in the initial SDK install I picked (somehow) just API level 17, whereas the feature I wanted required API level 19. I went back and downloaded both 19 and 23 (the latest) which took forever. Finally, I was up and running!


Tuesday, December 29, 2015

Dropdown and Popover services in AngularStrap

As per a previous post, I have been using AngularStrap to combine the strength of AngularJS with the beauty of Bootstrap widgets. I think it is fair to say that it has not been a smooth ride. Part of the reason is the API docs for AngularStrap are far from complete or even correct.

Today, I was trying to incorporate a dropdown (a context menu, really) and ran into a case where the documentation does not show how exactly to use the $dropdown service (to launch the popup from the controller).

Looking at the source, I found that there is a show() method similar to other services in their collection. However, this did not quite work and I ended up with a runtime error:

TypeError: Cannot read property 'link' of undefined

Googling around I found this plunk that supposedly showed the correct way of using the $dropdown service. However, this did not help my situation and I was left with the same error.

Scratching my head some more and looking around, I found this post about using the $popover service, which works in the same way as the $dropdown one. It suggested that $promise has to be used rather than just calling show() directly. It was unclear what $promise exactly is, and again looking at the source for the tooltip module, which is the "base" for the dropdown module, it turns be a property computed from the Angular compilation of bootstrap content. Looking further, the $bsCompiler module does a bunch of stuff with the template asynchronously (using the $q service). So that was the explanation for why I needed to show the dropdown in this way:

    dropdown.$promise.then(function () {
dropdown.show();
   });

This did work and my dropdown (context menu) did show and work properly.

Sunday, December 13, 2015

Bazillion New Technologies

Here are slides of a talk I gave today. The talk aims to give the attendees a broad overview of "hot" technologies in various fields of IT. The fields are by no means extensive, as time was limited. 

Thursday, November 26, 2015

Drag and Drop with Angular

In my last post, I implemented drag and drop with clone using JQuery. Now, it was time to integrate it into an application I am building, and thus had to "angularize" the implementation.

There are many drag and drop implementations on Angular out there.

The Angular docs include a simple example on directives that add/handle event listeners to implement dragging. Unfortunately, it is pretty rudimentary and it does not support cloning the draggable.

This one by Ben Parker builds from scratch on top of angular without using JQuery UI. It is an interesting approach but it is more pedagogical than anything else since it misses out on all the goodies provided by JQuery UI and its plugins.

This one by Amit Gharat combines the power of JQuery UI and Angular declarative clarity. However, it was too constraining for my needs. To use it, the drag source and drop target both have to have an underlying model and all manipulation happens to the model. If you needed to further manipulate to the dropped object, you would have to write some custom handlers. Besides, I found some oddities when trying it out, like behaving in a strange way if you did not add certain attributes.

Other implementations such as ngDraggable had similar issues.

After this tour, I decided to roll my own. I did not need something generic so I wrote a narrow solution that fit my needs. The code is basically the same that I posted in my last post but wrapped in directives and controllers.

angular.module('coach.field', [])
.directive("cloneDraggable", function() {
return {
link: function(scope, element, attrs, controller) {
element.draggable({ helper:'clone', 
                                                          revert: 'invalid', 
                                                          cursor: "crosshair"});
}
}
})
.controller("soccerFieldCtrl", function(tacticsService, $scope) {
$scope.idCounter = 0;
this.nextId = function() {
return $scope.idCounter++;
};
})
.directive("soccerField", function(tacticsService) {
return {
templateUrl: "field/field.html",
controller: "soccerFieldCtrl",
                link: function(scope, element, attrs, controller) {
          element.droppable({
drop: function(ev, ui) {
if (! ui.helper.hasClass("toolbar-gadget"))
return;

var dropped=$(ui.draggable).clone();
var newId = "player" + controller.nextId();
dropped.attr("id", newId);

var pos=$(ui.helper).offset();

var newX = pos.left- element.offset().left;
var newY = pos.top - element.offset().top;

dropped.css({"left":newX,"top":newY, "z-index": 100});
dropped.removeClass("toolbar-gadget");
dropped.addClass("player");

$(this).append(dropped);
       
                dropped.draggable({ cursor: "crosshair", 
                                                                          containment: 'parent'});
}
     });
}
}
});


Sunday, November 22, 2015

jQuery UI Drag & Drop with "Clone"

The problem I was trying to solve is how to drag an element, make a clone on drop, then make the dropped element draggable with different parameters. Seemed like a simple task, given the basics that are built into jQuery UI. It turns out that there a lot of posts out there that give part of the answer, but I have not found one that gives a complete example. Marcos Placona came close with his example, but it seemed overly complex and it also had an interesting bug:
  1. Drag one of the widgets on the left and drop in the grid (fine).
  2. Drag the widget you just dropped (fine).
  3. Now, drag any widget on the left to an invalid place, so as to force an animation back, and see what happens!
There seems to be some phantom association between the previously dropped element and the draggable element used by jQuery UI, either through direct reference or an ID.

I was about to adopt his code, but having found this bug I thought I should try on my own, given all the examples I have seen. I ended up building a much simpler working example with half the code.

A few notes on the code:
  1. The condition in the beginning of the drop() function filters out the case where you drag a widget that has already been dropped in the drop area.
  2. I set the position of the dropped element to "absolute" so that it can float inside the drop area.
  3. To calculate the drop position within the drop area, you need to calculate the offset of the dropped element from its parent, rather than from the page origin (which are the coordinates you get in the event).
  4. Note that you have to call css() on element before you append it or else the position may not take effect!
  5. Finally, for the code nazis out there, I deal with the repetition in the CSS via SASS when I develop locally!