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

How can I link to a route that resolves in two components? #118

Closed
PascalPrecht opened this Issue Feb 19, 2015 · 12 comments

Comments

Projects
None yet
6 participants
@PascalPrecht
Copy link
Contributor

PascalPrecht commented Feb 19, 2015

Let's say we have basic router configuration that has two routes configured. One maps to one component, the other one loads and instantiates let's say two components.

app.controller('AppController', function ($router) {
  $router.config([
    {
      path: '/',
      component: 'welcome'
    },
    {
      path: '/other-route',
      components: {
        viewportA: 'componentA',
        viewportB: 'componentB'
      }
  ]);
});

Let's assume we have all templates and controller defined, so that this setup actually works.

Now we want to add a routerLink to the welcome component, to link to /other-route. Usually, routerLink expects a component name. So what we can do is:

<a router-link="componentName">Link to component foo</a>

But our configured /other-route comes with two components. So how do we navigate to that sort of "state"? Is that something that should be handled by routerLink at all, or should I go back to plain old anchor tag?

Also, when happens if we want to navigate to that route, and configure all it's components with $routeParams?

For one component we can do sth. like:

<a router-link="user({id: app.user.id})">{{app.user.name}}</a>

Whereas the user component might have it's route configured like /user/:id. How would that work if a route has more than one component that can also be configured with parameters?

@btford

This comment has been minimized.

Copy link
Contributor

btford commented Feb 26, 2015

I've been thinking about this as well.

For now, you should be able to do either/or.

I'm thinking of introducing a "name" field for each potential route. Thoughts?

@btford btford added this to the post ng-conf milestone Feb 26, 2015

@PascalPrecht

This comment has been minimized.

Copy link
Contributor

PascalPrecht commented Feb 26, 2015

Like the state name in ui-router?

@btford

This comment has been minimized.

Copy link
Contributor

btford commented Feb 26, 2015

yeah, exactly.

then by "convention" single-level routes have the same name as the
component.

On Thu, Feb 26, 2015 at 1:36 PM Pascal Precht notifications@github.com
wrote:

Like the state name in ui-router?


Reply to this email directly or view it on GitHub
#118 (comment).

@jvandemo

This comment has been minimized.

Copy link
Contributor

jvandemo commented Mar 2, 2015

Would it make sense to combine both component and components like this?

Markup index.html:

<div ng-viewport></div>

Markup components/outer/outer.html:

<h1>Outer</h1>
<div ng-viewport="innerOne"></div>
<div ng-viewport="innerTwo"></div>

Route config:

app.controller('AppController', function ($router) {
  $router.config([
    {
      path: '/some-route',

      // Load components/outer/outer.html in default viewport
      // Instantiate OuterController
      component: 'outer',

      // Fill the named viewports in components/outer/outer.html
      components: {
        innerOne: 'componentA',
        innerTwo: 'componentB'
      }
  ]);
});

This would cause:

  • the route to have a name (string outer) that could be using in ng-link
  • an extra hook to be available in the logical hierarchy by having an OuterController available

So in essence it would be similar to using a name key but with the added benefit of having an additional controller available, which could be useful if you need to resolve data shared in both inner viewports.

Would that make sense?

@btford

This comment has been minimized.

Copy link
Contributor

btford commented Mar 4, 2015

@jvandemo – I like it except that I think it's confusing to have two similarly named things that behave so differently.

We should probably separate out the property that represents the name you link to from the property that represents what gets loaded.

Other than that, great proposal. Thanks for taking the time to write it up. :)

@jvandemo

This comment has been minimized.

Copy link
Contributor

jvandemo commented Mar 4, 2015

@btford - You're right, that makes most sense and will provide the most intuitive API from a user perspective.

I'll think of some real use-cases where combinations could be beneficial to see if it would actually be useful to implement this or not.

I don't think it offers anything new that's not possible yet, however it could possibly save lines of code and prevent creation of "dummy" components in case you need to wrap a controller around sibling viewports.

Feel free to let me know if I can be of any help with this.

Thanks for the feedback!

@btford

This comment has been minimized.

Copy link
Contributor

btford commented Mar 4, 2015

Route recognizer exposes this with a property called as – here's what I propose:

// "component" is an alias for "components"
// the name is exposed with the "as" property, and defaults to the name of the "default" viewport's component
{ path: '/', component: 'a' } => { path: '/', components: { default: 'a' }, as: 'a' }
{ path: '/', components: 'a' } => { path: '/', components: { default: 'a' }, as: 'a' }

// using both properties throws an Error
{ path: '/', component: 'a', components: 'b' } => Error

// when there's no default viewport, and no "as," you reference the route with "{{viewportName}}:{{componentName}}"
// note that this means you'll have multiple ways to refer to the same route
{ path: '/', components: {main: 'a', side: 'b' } } =>
      { path: '/', components: {main: 'a', side: 'b' }, as 'main:a' }
      { path: '/', components: {main: 'a', side: 'b' }, as 'side:b' }

// if you have an "as," you just reference that
{ path: '/', components: {main: 'a', side: 'b' }, as 'foo' } =>
      { path: '/', components: {main: 'a', side: 'b' }, as 'foo' }

@btford btford closed this in 58853bd Mar 4, 2015

@btford

This comment has been minimized.

Copy link
Contributor

btford commented Mar 4, 2015

I went and implemented it because it was pretty easy.

I'm happy to bikeshed on it a bit if anyone's interested.

@jvandemo

This comment has been minimized.

Copy link
Contributor

jvandemo commented Mar 4, 2015

@btford — Thanks for the quick fix! Will be playing around with it and let you know if I experience unexpected behavior. Awesome work!!

@rohanrehman

This comment has been minimized.

Copy link

rohanrehman commented Apr 4, 2015

@btford the ":" were missing right?

{ path: '/', components: {main: 'a', side: 'b' }, as 'foo' }
{ path: '/', components: {main: 'a', side: 'b' }, as:'foo' } =>
      { path: '/', components: {main: 'a', side: 'b' }, as:'foo' }
@jakob-e

This comment has been minimized.

Copy link

jakob-e commented Sep 21, 2015

Question what does component point to?

Singular (the property):
component : 'welcome' or
component : { main:'a', side:'b' }

Plural (the content)
components : ['welcome'] or
components : [{ main:'a' },{ side:'b' }] or
components : { main:'a' , side:'b' }

IMO the singular version is more intuitive (thinking key value pairs as a component is not wrong but a little abstract) and I suggest the 's version be removed to prevent confusion, unnecessary code and handling.

@playground

This comment has been minimized.

Copy link

playground commented Nov 11, 2015

Hi,
I can't get route to work. <ng-viewport> is blank. What am I missing? I'm running Angular 1.4.5. Thanks.

jspm config
"angular": "github:angular/bower-angular@1.4.5",
"angular-animate": "github:angular/bower-angular-animate@1.4.5",
"angular-new-router": "npm:angular-new-router@0.5.3",
"angular-sanitize": "github:angular/bower-angular-sanitize@1.4.5",
"angular-messages": "github:angular/bower-angular-messages@1.4.5",
"css": "github:systemjs/plugin-css@0.1.19",
"foundation": "github:zurb/bower-foundation@5.5.3",
"json": "github:systemjs/plugin-json@0.1.0",
"scss": "github:theefer/plugin-sass@master",
"text": "github:systemjs/plugin-text@0.0.3",
"typescript": "npm:typescript@1.6.2",

index.html

<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>New router</title>
    <!-- SystemJS -->
    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>
      System.import('app/app'); // make sure any errors are print to console
    </script>

  </head>
  <body>
  <ng-viewport></ng-viewport>
  </body>
</html>

app.js

import mainModule from './main';

console.log('mainmodule: ', mainModule);
angular.element(document).ready(function() {
console.log(mainModule.name);
angular.bootstrap(document, [mainModule.name], {
strictDi: true
});
});

main.js

import angular from 'angular';

import WUMainController from './wu-main-controller';

console.log(angular, WUMainController);

let mainModule = angular.module('app', [
'ngNewRouter',
'ngMessages',
'ngAnimate',
'ngSanitize'

])
.controller(MainController.name, MainController);

export default mainModule;

main-controller.js

class MainController {
constructor($router) {
$router.config([
{ path: '/', redirectTo: '/home'},
{ path: '/home', component: 'home'}
]);
}
}

MainController.$inject = ['$router'];

export default MainController;

components/home/home.js

class HomeController {
constructor() {
this.title = 'testing';
}
}

export default HomeController;

components/home/home.html

<div>{{home.title}}</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment