Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@noView on view-model navigated to by router throws TypeError in aurelia-templating #415

Open
carusology opened this issue Jul 6, 2016 · 11 comments

Comments

@carusology
Copy link

It is possible to create a custom element without a view by applying the @noView annotation on top of that custom element's view model. However, if you do the same thing to a view that is the target of a route, this line in Controller.automate() in aurelia-templating blows up because it assumes a view property to be defined that is not.

Here is a gist.run that shows the issue. If you remove the @noView annotation from route.js, the route renders correctly.

https://gist.run/?id=14a083656624a84e51731baae5511e55

After lots of reading, the closest documentation I have found on the subject is via @EisenbergEffect on Issue #238:

[C]urrently, the router enforces that all view models that get rendered must have a View. We may be able to change that in the future though.

It sounds like this just happens to be how it works, rather than desired behavior. Should I expect this hard requirement to change? If not, what should I be doing when I do not have anything for the router to render?

@EisenbergEffect
Copy link
Contributor

What does it mean to navigate to a route and not render anything? What should the router-view do to represent that?

@Thanood
Copy link

Thanood commented Jul 6, 2016

Empty viewPorts come to my mind. As a fallback for routes that don't apply a viewPort. Something like noToolbar.js.

@carusology
Copy link
Author

Apologizes, a bad choice of words. Of course I want to render something. What I do not have is anything to put into a template-based *.html file.

Maybe specificity will help.

I am using Auth0's "Lock" widget on a login page, and all of the relevant content will be rendered via a call to its show() method. It even throws up a mask under the prompt. Right now I'm calling show() in the attached() function on my login view model, and I don't really have anything to put into the view. That's when I tried to use @noView, and that's how I ran into this restriction.

@carusology
Copy link
Author

carusology commented Jul 6, 2016

Here's the current state of my view model.

import { inject, noView } from 'aurelia-framework';
import { Router } from 'aurelia-router';

import Auth0Lock from 'auth0-lock';
import AuthenticationContext from './context';

@inject(AuthenticationContext, Router)
@noView
export default class Login {

  _lock = new Auth0Lock('<MY_CLIENT_ID>', '<MY_AUTH0_DOMAIN>');

  constructor(context, router) {
    this._context = context;
    this._router = router;
  }

  activate(params) {
    this._redirectUrl = params.redirect_url || '/';
  }

  attached() {
    this._lock.show(
      {
        closable: false
      },
      (err, profile, id_token) => {
        if (err) {
          console.log(err);
        } else {
          this._context.login(profile, id_token);
          this._router.navigate(this._redirectUrl);
        }
      }
    );
  }

}

@EisenbergEffect
Copy link
Contributor

What does that do? Does it show a popover?
What would you expect to happen to the previous screen that you navigated from, when you navigate to something with no view.

@carusology
Copy link
Author

carusology commented Jul 6, 2016

What does that do? Does it show a popover?

Yep. Here's a demo.

What would you expect to happen to the previous screen that you navigated from, when you navigate to something with no view.

The previous screen I navigated from was being serviced by the same router. So, in my context, I was expecting the content inside of <router-view></router-view> from the previous view to be removed, and that nothing would be inserted into its place. <router-view></router-view> would have no children.

@EisenbergEffect EisenbergEffect self-assigned this Jul 7, 2016
@EisenbergEffect
Copy link
Contributor

EisenbergEffect commented Jul 7, 2016

Ok, let me think about this. I can see a couple scenarios. Besides your own, someone actually might want to do their own custom rendering and then have that pushed into the router-view. I'm thinking that the router view should check if the view is null, if it is, it checks the view model to see if there's a view property maybe? and if there is, it uses that as the view. If not, then it renders nothing. Need to ponder more...

@carusology
Copy link
Author

Besides your own, someone actually might want to do their own custom rendering and then have that pushed into the router-view.

For sure. While the third-party code I am using ignores the location of <router-view></router-view> in the DOM hierarchy and places a modal dialog over everything in the viewport, it could just as well have expected a parent element to be provided into which it would programmatically inject its contents. If that has been the case, I would have expected to use something like the Element dependency from the aurelia-framework module that refers to the <router-view>, though I understand that <router-view> is the parent of the view's root element rather than the root element itself.

Maybe the views navigated to by the router could generate a custom element to use as a root element that would be the sole child of a <router-view> element? That would make the view's existence in the DOM hierarchy identical whether it is rendered by the router or as a custom element defined in another view's *.html file. Then the Element dependency injected into the view model would look the same.

By the way, take all of this from someone with about a month's experience with the framework. I may be completely failing to grasp the correct interaction of the router, views, and view models.

@brandonseydel
Copy link
Member

brandonseydel commented Jul 18, 2016

//explicit
@noView('getHtml()')
//implicit (lloks for view()
@noView(true)
//@noView/@noView()/@noView(false)  -default 
export class DynamicView
{
     //returns promise
     getHtml(){
        return this.getHtmlPage();
    }

    //returns promise
    view(){
        return this.getHtmlPage();
    }
}

This makes sense to me...then run it through the compiler and stuff onto the page.

@EisenbergEffect
Copy link
Contributor

You can always create your own view strategies or simply implement getViewStrategy() to return a custom view.

@m-andrew-albright
Copy link

m-andrew-albright commented Sep 19, 2017

Attempting to use a react component as the module targeted by a router configuration, I am attempting to use @noView (or even getViewStrategy() { return NoViewStrategy; }) to specify that the custom-element will handle rendering its own view, but I am getting the error described in this issue

image

For now, the work-around for this situation is to switch such that this module is a normal aurelia view-model, which wraps a single aurelia custom element which will make use of the @noView decorator and use react to render its view.

(edit* I just found this: #550 which contains more insight and is helpful in this particular situation)

@EisenbergEffect EisenbergEffect removed their assignment Dec 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants