Tag Archives: Web

Dynamic List Items in an Ionic/AngularJS App

In an Ionic/AngularJS app when one wants to display a list of model objects, the following will typically be used:

<ion-list>
  <ion-item ng-repeat="item in items">
    Hello, {{item}}!
  </ion-item>
</ion-list>

In an app I’m currently working on, however, I wanted to make use of different items in a list dynamically, with the appearance of each item depending on various properties of the given model object in the list. I’d imagine that to solve this problem there are various ways of doing so, but I ended up using html view templates and the ng-include directive to achieve this. Below is a step-by-step walkthrough of the method I used:

  • Define HTML view templates for the different list items to be displayed.

TemplateA.html

{{modelObject.name}}

TemplateB.html

<img class="full-image" ng-src="{{modelObject.image.url}}">
<p>
	{{modelObject.description}}
</p>
  • Add functions in the controller to determine the correct class & view template to use based on properties of the provided model object.

HomeCtrl.js

.controller('HomeCtrl', function($scope) {
  var vm = $scope;

  // Determines the correct CSS class to use based
  // on properties of the provided model object
  vm.itemClass = function(modelObject) {
    if (modelObject.type == 0) {
      return "class-A";
    }
    else {
      return "class-B"
    }
  };

  // Determines the correct html view template to use based
  // on properties of the provided model object
  vm.itemTemplate = function(modelObject) {
    if (modelObject.type == 0) {
      return "app/path_to_template/templateA.html";
    }
    else {
      return "app/path_to_template/templateB.html";
    }
  };
});
  • Then in the view displaying the list, it’s as simple as referencing the relevant controller functions to dynamically determine the correct class and template to use for each item in the list at runtime.

Home.html

    <ion-list>
      <ion-item ng-repeat="modelObject in modelObjects" ng-class="itemClass(modelObject)">
        <ng-include src="itemTemplate(modelObject)"></ng-include>
      </ion-item>
    </ion-list>

Uploading a base64 image to Parse with the REST API in AngularJS

Screen Shot 2015-05-31 at 8.34.44 PM

I was recently working on an Ionic/AngularJS app which needed to do the following:

– Upload a base64 image file (taken with the camera) to the Parse servers using the REST API.

– Associate the uploaded image file with an object and save the object to Parse using the REST API.

 

The Parse documentation didn’t seem to explain this specific case and other examples online seemed to all offer different details on how to get this done… so I ended up jumping through a few hoops until I eventually got it working. Below is an example of what I used to achieve this.

ImageSubmissionCtrl

// camera is simply an injected service, wrapping the cordova APIs
.controller('ImageSubmissionCtrl', function($scope, $http, camera) {

  var vm = $scope;
  var imageData;

  // Object to save to Parse that includes an image
  var object = {
    text: "",
    image: null
  };

  // Function to take a picture using the device camera
  vm.takePicture = function() {

    // Define various properties for getting an image using the camera
    var cameraOptions = {
      quality : 75,
      // This ensures the actual base64 data is returned, and not the file URI
      destinationType: Camera.DestinationType.DATA_URL,
      encodingType : Camera.EncodingType.JPEG
    };

    // Use the Cordova Camera APIs to get a picture. For brevity, camera
    // is simply an injected service
    camera.getPicture(cameraOptions).then(function(returnedImageData) {
      imageData = returnedImageData;

    }, function(err) {
      console.log("Error taking picture: " + err);
    });
  };

  // Function to submit the object to Parse using the REST API
  vm.submitObject = function() {

    // This part is important. As part of the JSON that we send to Parse,
    // we need to specify the content type here as a field(__ContentType)
    // along with the image data. Notice that the Content-Type specified
    // in the headers is actually "plain/text"
    var dataToSubmit = {__ContentType : "image/jpeg", base64 : imageData};

    // First upload the image file
    $http.post("https://api.parse.com/1/files/image.jpg", dataToSubmit, {
           headers: {
               "X-Parse-Application-Id": PARSE_APP_ID,
               "X-Parse-REST-API-Key": PARSE_REST_API_KEY,
               "Content-Type": "plain/text"
           }
    })
    .success(function(result) {
      // Now associated the image file with the object
      coupleImageFileWithObject(result.name);
    })
    .error(function(result) {
      console.log("Error uploading image file: " + err);
    });
  };

  // Function to associate the image file with an object and save the
  // object to Parse using the REST API
  function coupleImageFileWithObject(fileName) {

    // Assign the filename to our object prior to saving it to Parse
    object.image = {name : fileName, __type : "File"};

    // The 'ObjectClass' in the url should be replaced by the class name
    // of the object you are saving
    $http.post("https://api.parse.com/1/classes/ObjectClass", object, {
           headers: {
               "X-Parse-Application-Id": PARSE_APP_ID,
               "X-Parse-REST-API-Key": PARSE_REST_API_KEY
             }
      })
      .success(function(result) {
        console.log("Object successfully saved.");
      })
      .error(function(result) {
        console.log("Error coupling image file with object: " + err);
      });
  };
});

It’s important to understand that the first step is to upload the file to Parse independently of the containing object, and then only on a successful response associate the file handle with the object and save the object itself to Parse.

 

Android WebView flicker when using hardware acceleration on Android 3.0+

There is an Android bug where WebViews may present an ugly flicker when being used on 3.0+ devices with Hardware Acceleration enabled. I was busy with an update to an Android app I’m working on which makes use of a WebView that slides in and out (using this awesome Sliding Menu library), when I noticed the *delightful* surprise when sliding the WebView back in:

Not ideal, is it?

Not ideal, is it?

As much as I can’t believe this kind of bug still exists, especially considering it seems to have been around for some time, it lives with us and thus we need to use some kind of workaround.  I immediately turned to SO for help and found a possible workaround:

WebView “flashing” with white background if hardware acceleration is enabled (Android 3.0+)

The workaround involves using a method that is only available from API level 11 (HoneyComb), and considering my app is targeting a minimum level of 8 I used the following code:

/**
 * Initializes the WebView:
 * - Configures the WebView settings
 * - Adds a WebViewClient
 * - Custom config of the webview
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void initWebView()
{
	// Other init code
	
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
	{
		// This is added as a work-around for the flicker which occurs in Android 3.0+
		// when hardware acceleration is enabled:
		// http://stackoverflow.com/questions/9476151/webview-flashing-with-white-background-if-hardware-acceleration-is-enabled-an
		getWebView().setLayerType(View.LAYER_TYPE_SOFTWARE, null);
	}
}

So pick your poison: reduced performance or flickering?

Android WebView Scaling

Just as it’s important for an Android developer to understand how to support multiple screen sizes, so too is it important to understand how the Android framework handles the scaling of the content in a WebView.

To demonstrate the scaling that takes place within a webview, I’m going to use a basic example of a webview that displays a local image and some text underneath it – as some additional information, the device used in this example is a Galaxy Nexus with an xhdpi screen (320 dpi) and resolution of 1280×720. Below is the HTML and CSS used and the result of the app run on the said device:

<html>
    <head>
        <link rel="stylesheet" type="text/css" href="sample.css" />
    </head>
    <body>
        <img src="localImage.png"/>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipisicing elit<br>
            bla bla bla
        </p>
   </body>
</html>

the CSS…

img
{
    display: block;
    margin-left: auto;
    margin-right: auto;
}

p
{
	background-color: #E4E4E4;
	padding:1em;
	margin:0.5em;
	border-radius: 15px;
	font-size: 1em;
}

and finally the result…

Web content with default scaling.

Web content with default scaling.

Immediately it becomes obvious that the 300×200 local image has been scaled up considering the resolution of the device. Essentially what the Android framework is doing is assuming that the web content is targeted at an mdpi density (which Android treats as the base density), and as a result scales the content up accordingly for the xhdpi test device so that the drawn elements match the physical size they would appear on an mdpi display. Unless you explicitly specify the density you are targeting, Android will scale up/down accordingly.

To adjust the scaling performed by the Android framework, one can use the viewport meta tag to specify properties regarding screen density support:

<meta name="viewport" content="target-densitydpi=device-dpi" />

The Android docs explain the target-densitydpi property as follows:

You can use this to specify the target density for which the web page is designed, using the following values:

  • device-dpi – Use the device’s native dpi as the target dpi. Default scaling never occurs.
  • high-dpi – Use hdpi as the target dpi. Medium and low density screens scale down as appropriate.
  • medium-dpi – Use mdpi as the target dpi. High density screens scale up and low density screens scale down. This is also the default behavior.
  • low-dpi – Use ldpi as the target dpi. Medium and high density screens scale up as appropriate.
  •  – Specify a dpi value to use as the target dpi (accepted values are 70-400).

So if we use this information and modify our HTML to prevent default scaling:

<html>
    <head>
        <link rel="stylesheet" type="text/css" href="sample.css" />
        <meta name="viewport" content="target-densitydpi=device-dpi" />
    </head>
    <body>
        <img src="localImage.png"/>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipisicing elit<br>
            bla bla bla
        </p>
   </body>
</html>

and run the test app again, we get:

Web content with no scaling

Web content with no scaling

One can now see that no scaling has taken place; the image is displayed as one would expect a 300×200 image on such a device, and the text is significantly smaller. Without the scaling it becomes obvious that the graphic and styles used are not suitable for the xhdpi device, so these would ultimately need to change yet still cater for other densities.

In many simple cases like our example, all we want is to be able to develop and test the web content against a specific test device to ensure that it looks correct, and then allow Android to scale up/down from there. To achieve this, one can declare the specific target density (or even the exact dpi) for which your content is being designed. The following demonstrates this using our example designed for the Galaxy Nexus (320 dpi):

<html>
    <head>
        <link rel="stylesheet" type="text/css" href="sample.css" />
        <meta name="viewport" content="target-densitydpi=320" />
    </head>
    <body>
        <img src="localImage.png"/>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipisicing elit<br>
            bla bla bla
        </p>
   </body>
</html>

 

img
{
    display: block;
    margin-left: auto;
    margin-right: auto;
}

p
{
	background-color: #E4E4E4;
	padding:1em;
	margin:0.5em;
	border-radius: 15px;
	font-size: 2em;
}

With the CSS modified a bit for the higher density and a new higher resolution graphic, we see the following result:

Web content targeted at xhdpi

Web content targeted at xhdpi

We are now happy with the look of the web content on our device, and because we have told the Android framework the specific density we are targeting it will automatically scale up or down for devices with higher or lower densities respectively. The following is a screenshot of the same HTML/CSS and graphic on a lower density emulator:

Web content on an hdpi emulator

Web content on an hdpi emulator

Having said all of this, YMMV with this basic approach. Allowing Android to perform scaling like this may have undesirable results with certain aspects, such as image quality. A more in-depth method for dealing with web content and multiple screen sizes and densities is to provide specific styles/graphics for different densities using the CSS media feature; more information about this can be seen here.

Custom Web Signature in Gmail

Image

If you have ever tried to add a fixed Gmail signature using the general settings, you may have noticed that the input doesn’t allow for raw HTML to be used. Whilst in most cases this probably isn’t a problem, it can be a little limiting in terms of how custom one can make their signature…for instance one may want hyperlinks and images as part of their mail signature.

There is a fairly easy way to include web content within your Gmail signature:

  1. Write your html content using whatever editor you like.
  2. Render the html (in a browser or JS Fiddle window).
  3. Select all of the rendered output, copy and then paste the output into the signature input box in the general settings of Gmail.

To show this method as an example, I’ve created a sample signature. To add this as a Gmail signature, select all from the result window, and then paste in your Gmail signature input box as follows:

Image

Save changes and that’s that!

Now you might be thinking that one could customize even further and use all kinds of custom fonts in the CSS (such as using google web fonts), however, it appears that Gmail does not allow custom fonts outside of the standard set already provided. Whilst a custom font is not a necessity, I thought it would be nice to find a way around this, albeit a crude one: what I did was to use an image instead (Yes, I said it was crude), which unfortunately also comes with the following limitations:

  • Multiple hyperlinks in the signature will not work.
  • The image may not scale well.

For straightforward signatures with one hyperlink, this method can work by making the entire image a hyperlink out to whatever address you like. To achieve this you can use the following steps:

  1. Write your html content using whatever editor you like.
  2. Render the html (in a browser or JS Fiddle window).
  3. Take a screenshot of the result, cut out the signature portion and save as a new image.
  4. Upload the image to an image hosting site (such as TinyPic) and take note of the image url.
  5. Use this example and replace the image and target urls as needed.
  6. Select the result, copy and then paste as input for your Gmail signature (as shown in the first example).
  7. Save changes in your Gmail general settings.

You should now have an image as your signature which links out to the target url when clicked. It’s not ideal, but may be suitable for your purposes if you wish to use more custom fonts.