Core: [Proposal] Expose additional global helpers for use in views: url() and assets()

Created on 14 Sep 2016  路  11Comments  路  Source: adonisjs/core

It would be great if, like Laravel, Adonis could expose two additional URL helpers inside views: url() and assets().

As it stands, I have two middleware for providing these features in my application, but believe others can benefit from having these available out-of-the-box.

The below ViewUrl.js class

app/Http/MIddleware/ViewUrl.js
'use strict'

const View = use('View')

class ViewUrl {

  * handle (request, response, next) {

    let baseUrl = request.secure()? 'https://' : 'http://'
    baseUrl += request.headers().host + '/'

    View.global('url', (path) => {
      if(typeof path != 'undefined') {
        path = (path.substring(0, 1) == '/')
          ? path.substring(1)
          : path
        return baseUrl + path
      }
      return baseUrl
    })

    yield next
  }

}

module.exports = ViewUrl

provides the ability to do the below in a view:

<a href="{{ url('sign-in') }}">Sign In</a>

which renders:

<a href="http://my-domain.com/sign-in">Sign In</a>

And the below ViewAssets.js class:

app/Http/MIddleware/ViewUrl.js
'use strict'

const View = use('View')

class ViewAssets {

  * handle (request, response, next) {

    let baseUrl = request.secure()? 'https://' : 'http://'
    baseUrl += request.headers().host + '/assets/'

    View.global('assets', (assetPath) => {
      assetPath = (assetPath.substring(0, 1) == '/')
        ? assetPath.substring(1)
        : assetPath
      return baseUrl + assetPath
    })

    yield next
  }

}

module.exports = ViewAssets

provides the ability to do the below in a view:

<link rel="stylesheet" type="text/css" href="{{ assets('css/styles.css') }}" />

which renders:

<link rel="stylesheet" type="text/css" href="http://my-domain.com/assets/css/styles.css" />

Most helpful comment

@thetutlage I have just come across a situation where this proposal is somewhat relevant.

When generating URL's for use in emails. As it stands I need to hard code my URL in my email templates like so:

<a href="https://my-domain.com/verify?token={{ verification_token }}">Click here to verify your account</a>

What do you think?

All 11 comments

Why do you want to use absolute URL's?

To be honest I'm not sure :smile: I guess I'm just used to the syntax from working with my Laravel projects.

Happy to close this if you feel it is unnecessary.

@nicklaw5 Yes, I don't see any reason of adding absolute URL's.

Closing the issue, feel free to report any future issues

@thetutlage I have just come across a situation where this proposal is somewhat relevant.

When generating URL's for use in emails. As it stands I need to hard code my URL in my email templates like so:

<a href="https://my-domain.com/verify?token={{ verification_token }}">Click here to verify your account</a>

What do you think?

Question then : how we can add assets/js/* in template?

@thetutlage I use linkTo() in mail template but it cannot generate a absolute url with hostname

I am having a similar issue. I am using wkhtmltopdf which requires absolute URLs to load external assets (images, css, js). I'm using APP_URL from env, but I would prefer it if this was available as a helper function so I don't have to specify baseUrl per environment.

I solved for this in v4 using the following View global defined in hooks.js [hooks.after.providersBooted] (adapted from the solution @nicklaw5 posted above) which might be helpful for others:

View.global('absoluteUrl', function (path) {
  const req = this.resolve('request')
  let baseUrl = req.secure() ? 'https://' : 'http://'
  baseUrl += req.headers().host + '/'
  if (typeof path !== 'undefined') {
    path = (path.substring(0, 1) === '/')
      ? path.substring(1)
      : path
    return baseUrl + path
  }
  return baseUrl
})

I solved for this in v4 using the following View global defined in hooks.js [hooks.after.providersBooted] (adapted from the solution @nicklaw5 posted above) which might be helpful for others:

View.global('absoluteUrl', function (path) {
  const req = this.resolve('request')
  let baseUrl = req.secure() ? 'https://' : 'http://'
  baseUrl += req.headers().host + '/'
  if (typeof path !== 'undefined') {
    path = (path.substring(0, 1) === '/')
      ? path.substring(1)
      : path
    return baseUrl + path
  }
  return baseUrl
})

This worked nicely for me, coming from Laravel I am used to sending out emails with activation and token verified links in so this feature was needed. The above code worked fine in normal views but to make it work for emails I had to pass the request object into the email view.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

amrayoub picture amrayoub  路  4Comments

krunaldodiya picture krunaldodiya  路  3Comments

milosdakic picture milosdakic  路  3Comments

navdeepsingh picture navdeepsingh  路  3Comments

themodernpk picture themodernpk  路  3Comments