Robert Kühne
Robert Kühne

Reputation: 908

Grails asset images in AngularJS templates

I'm using Grails 2.4.4 and AngularJS 1.3.15 to create a simple application. To make templates work with Grails I use the AngularJS Template Asset-Pipeline Plugin 2.0.7.

My first prototype was not using any routing logic from ngRoute. Now I want to extract parts of the growing application and put them in separate templates. This almost worked but I have a problem with images. Previously I used constructs like this to load images as assets:

<img src="${assetPath(src: 'image.png')}">

That did work because the whole app was a .gsp page. Extracting the code into templates this processing does not happen anymore and the images cannot be loaded anymore.

My current workaround is:

<img src="../assets/image.png">

Obviously this technique has some drawbacks. Hardcoding the asset location with a relative path can be very fragile. Did I miss some nice feature or command that could help me here merging AngularJS with Asset Pipeline?

Upvotes: 2

Views: 910

Answers (2)

CSharp
CSharp

Reputation: 1486

I 'got around' this issue by adding an 'AssetService' to my Angularjs project.

angular.module('myApp.assets')
.service('AssetService', [ function () {

    this.getAssetDir = function() {
        return window.grailsSupport.assetsRoot;
    };

    this.getRootDir = function() {
        return window.grailsSupport.root;
    };
}]);

This requires some code in your Grails Layout File....

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title><g:layoutTitle default="MyApp"/></title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" href="${assetPath(src: 'favicon.ico')}" type="image/x-icon">
    <link rel="apple-touch-icon" href="${assetPath(src: 'apple-touch-icon.png')}">
    <link rel="apple-touch-icon" sizes="114x114" href="${assetPath(src: 'apple-touch-icon-retina.png')}">

    <!-- add this to your layout -->
    <g:javascript>
        window.grailsSupport = { 
            assetsRoot : '${ raw(asset.assetPath(src: '')) }',
            root : '${createLink(uri: '/')}' 
        };
    </g:javascript>

    <asset:stylesheet src="application.css"/>
    <asset:javascript src="application.js"/>
    <g:layoutHead/>
</head>

I got the window.grailsSupport code in an answer to another stack overflow question.

You can now use the AssetService to prefix your URLs in your controllers...

angular.module('MyApp.profile')
.controller('MyCtrl', [ 'AssetService', '$http', function(AssetService, $http) {

    var self = this;
    self.pathToAnonProfile = AssetService.getAssetDir() + "ppt_Anonymous.jpg";

    $http.get(AssetService.getRootDir() + 'api/v1/users').then(function(response)    {
    ....
    }, function(errResponse) {
    ....
    }); 
}]);

It could most likely be improved and you still need to mix gsp and pure Angular templates but it keeps the Asset path in a single service which can easily be modified.

Upvotes: 0

Steve Hole
Steve Hole

Reputation: 358

It looks like the tag and the corresponding assetPath() are broken in this respect. They do not appear to respect the serverURL setting in config.groovy or calculate the base path properly when rendering in a template.

I was able to work around the issue in a less fragile way using the createLink() tag to generate my path. It fixes the name of the asset controller, but I think it unlikely that they will change that.

In my case I was resolving some flag images within an AJAX callback.

<img src='${createLink(controller: "assets", action: "flags/16/US.png")}' />

Hopefully this works for you as well.

Upvotes: 0

Related Questions