0
votes

How can I use signalR with aurelia canActivate() and activate() page cycle? What I mean is... In my VM constructor I initilaize the signalR connection. in canActivate() or activate() methods I start the signalR connection. On the server side, in the Hub, when the client connects I get the data for the client and publish it to the connected client. So Aurelia client will get the data asynchroniously. So the page will be displayed empty, and when the data comes it will refresh it. But I want to wait for the data from the signalR hub before displaying the page.

So the workflof is this:

  1. VM constructor => Build the signalR connection with( HubConnectionBuilder)
  2. VM Constructor => Set connection events like "onConnected"
  3. VM activate() => Start the connection by calling this.connection.start();
  4. SignalR Hub.OnConnectedAsync() => get the data from DB
  5. SignalR Hub.OnConnectedAsync() => Send the data to the newly connected client only ( Clients.Client(Context.ConnectionId).SendAsync("onConnected", data);)
  6. VM onConnected event handler => gets the data and sets the model (this.model=data)

At the time when the workflow reaches step number 4, the page is already displayed empty.

VM

@autoinject
export class AlarmsVM {
  model: any;    
  connection: HubConnection;

  constructor() {
     this.connection = new HubConnectionBuilder()
        .withUrl("/alarmsHub")
        .configureLogging(LogLevel.Information)
        .build();

    this.connection.on("onConnected", (data) => this.model = data);
    this.connection.on("onUpdate", (data) => this.model = data);
  }

  async activate() {
    await this.connection.start().catch(err => console.error(err.toString()));
  }

  async deactivate() {
    await this.connection.stop();
  }
}

signalR Hub

public class AlarmsHub:Hub
{
    private readonly IMediator _mediator;

    public AlarmsHub(IMediator mediator)
    {
        _mediator = mediator;
    }

    public override async Task OnConnectedAsync()
    {
        var data = await _mediator.Send(new GetAlarmsQuery());
        await Clients.Client(Context.ConnectionId).SendAsync("onConnected", data);
    }

    ...
}
1

1 Answers

1
votes

According to the documentation, you can return a promise from activate() and the navigation will only occur when the promise resolves: https://aurelia.io/docs/api/router/interface/RoutableComponentActivate/method/activate/

EDIT

I misread your original question, you basically want the activate to resolve when the onConnected event is received. Wrap the resolution of onConnected in a promise in the activate() and you should be good to go, example code:

  activate() {
    this.connection.start().catch(err => console.error(err.toString()));
    return new Promise((resolve, reject) => {
       this.connection.on("onConnected", (data) => {
          this.model = data;
          return resolve();
       });
    });
  }