Manipulate logged in user object and return to all views

Here’s what I want to achieve:

For the current logged in user, I want to load the relationship, get some data and pass that so all views can use it (and not just the direct one that is called in the controller).

E.g.

User model:

  tasks() {
    return this.hasMany('App/Models/ProjectTask')
  }

that is usually done in the controller like so:

await auth.getUser().tasks().fetch()

Now onto harder stuff.
I want tasks to be displayed in the left hand side menu which is loaded in the template like so:

           @loggedIn
           @include('menus/index')
           @endloggedIn

Anyway, I can pass the data through the controller and get the variable in the menu, but once I’m on the different screen, variable will be null.

I have tried to pass the data by extending the view through start/hooks.js.

That works fine for simple things and already set strings and array that does not come from the database.

Then I have moved to create a separate class that can be used anywhere.

ServiceTest.js:

class ServiceTest {

  constructor(user) {
  this.user = user
}

  async getTasks() {
    const u = await this.user.tasks().fetch()
    return u.toJSON()
  }
}

module.exports = ServiceTest

Above outputs a nice json array, however passing that to hooks will give me Promise { <pending> } even though it is in JSON format. I cannot use await in hooks cause it can only be used in async method.

hooks.js

  View.global('tasks', function(user) {
    return new serviceTest(user).getTasks()
  })

menu view:

{{ tasks(auth.user) }}

I’ve tried other things as well but didn’t work (I don’t have the code for that to show it off).

Anyone have a suggestion on how to get data from the user relationship to the all views (or indirect view template)?

Also data that is passed to the view needs to be updated when db record changes.

Help? :s

edit:

I have even tried to create a base controller so all controllers extends from it:

class TaskController extends BaseController {
    constructor() {
        super()
    }
...
...

BaseController:

'use strict'


class BaseController {

  constructor() {
    this.tasks()
  }

  async tasks({ auth, view }) {
      const user = await auth.getUser()
      const task = await user.tasks().fetch()

      view.share({
          tasks: task.toJSON()
    })
  }

}

module.exports = BaseController

but then I am getting another error:

TypeError: Cannot destructure property `view` of 'undefined' or 'null'.

and it looks to me that it doesn’t like that method in the TaskController

tasks({view}) {
  return view.render('task.index')
}

Without extending the controller, {view} works just fine but after it doesn’t want it.

Please help :frowning: literally tried everything I could possible think of.

edit 100:

I did manage to solve the problem by creating a group route, create new middleware with the code I wanted and used view.share to pass the data to the views.

It works. But is it the right way of doing it? Could possibly there be a better solution?

Here’s the example in case anyone else is struggling.

Route.group('tasks', () => {
  Route.get('/',,....
...
}).prefix('/tasks').middleware(['auth', 'viewshare'])

kernel.js

const namedMiddleware = {
  auth: 'Adonis/Middleware/Auth',
  guest: 'App/Middleware/Guest',
...
...
  viewshare: 'App/Middleware/ViewShare'

viewshare middleware:

'use strict'

class ViewShare {
  async handle ({ auth, view }, next) {

      const user = await auth.getUser()
      const task = await user.tasks().fetch()

      view.share({
          tasks: task.toJSON()
    })

    await next()
  }
}

module.exports = ViewShare

Yes, middleware is the right way to do it.

Thanks for the confirmation.

Any idea why extending the controllers is giving me an error though?