<p dir="auto"><strong>I'm submitting a ...</strong> (check one with "x")</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="[ ] bug report =&gt; search github for a similar issue or PR before submitting
[X] feature request
[ ] support request =&gt; Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question"><pre class="notranslate"><code class="notranslate">[ ] bug report =&gt; search github for a similar issue or PR before submitting
[X] feature request
[ ] support request =&gt; Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
</code></pre></div>
<p dir="auto"><strong>Current behavior</strong><br>
When accessing modules lazily, RouteConfigLoadEnd gets fired once the factory gets loaded, but before routes are loaded and assigned to <code class="notranslate">route._loadedConfig</code>.</p>
<p dir="auto"><strong>Expected behavior</strong><br>
RouteConfigLoadEnd should be fired after <code class="notranslate">_loadedConfig</code> is assigned, or return routes as a parameter if it's fired from <code class="notranslate">RouterConfigLoader</code>.</p>
<p dir="auto">Change proposal:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="return map.call(moduleFactory$, (factory: NgModuleFactory&lt;any&gt;) =&gt; {
  const module = factory.create(parentInjector);
  const routes = flatten(module.injector.get(ROUTES));

  if (this.onLoadEndListener) {
    this.onLoadEndListener(route, routes);
  }

  return new LoadedRouterConfig(routes, module);
});"><pre class="notranslate"><span class="pl-k">return</span> <span class="pl-s1">map</span><span class="pl-kos">.</span><span class="pl-en">call</span><span class="pl-kos">(</span><span class="pl-s1">moduleFactory$</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-s1">factory</span>: <span class="pl-smi">NgModuleFactory</span><span class="pl-kos">&lt;</span><span class="pl-smi">any</span><span class="pl-kos">&gt;</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-smi">module</span> <span class="pl-c1">=</span> <span class="pl-s1">factory</span><span class="pl-kos">.</span><span class="pl-en">create</span><span class="pl-kos">(</span><span class="pl-s1">parentInjector</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-s1">routes</span> <span class="pl-c1">=</span> <span class="pl-en">flatten</span><span class="pl-kos">(</span><span class="pl-smi">module</span><span class="pl-kos">.</span><span class="pl-c1">injector</span><span class="pl-kos">.</span><span class="pl-en">get</span><span class="pl-kos">(</span><span class="pl-smi">ROUTES</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

  <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">onLoadEndListener</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-en">onLoadEndListener</span><span class="pl-kos">(</span><span class="pl-s1">route</span><span class="pl-kos">,</span> <span class="pl-s1">routes</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>

  <span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">LoadedRouterConfig</span><span class="pl-kos">(</span><span class="pl-s1">routes</span><span class="pl-kos">,</span> <span class="pl-smi">module</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto"><strong>What is the motivation / use case for changing the behavior?</strong><br>
Most common use case of <code class="notranslate">RouteConfigLoadEnd</code> is to react once lazy loaded routes are loaded. In <a href="https://github.com/Greentube/localize-router">localize-router</a> we can use this information for routes localization. However if even is fired before routes are de facto available in <code class="notranslate">_loadedConfig</code> and/or it doesn't provide this information it makes the entire event unusable as it's not that different from RouteConfigLoadStart.</p>
<p dir="auto">Issue is already mentioned here: <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="202153216" data-permission-text="Title is private" data-url="https://github.com/angular/angular/issues/14036" data-hovercard-type="issue" data-hovercard-url="/angular/angular/issues/14036/hovercard" href="https://github.com/angular/angular/issues/14036">#14036</a></p>
<ul dir="auto">
<li><strong>Angular version:</strong> 4.0.X</li>
</ul>

<ul dir="auto">
<li>
<p dir="auto"><strong>Browser:</strong> all</p>
</li>
<li>
<p dir="auto"><strong>Language:</strong> all</p>
</li>
</ul>
<h1 dir="auto">🚀 feature request</h1>
<h3 dir="auto">Relevant Package</h3>
<p dir="auto">This feature request is for @angular/router</p>
<h3 dir="auto">Description</h3>
<p dir="auto">Consider populating the router.config…children array the same for static and lazy loaded routes.</p>
<h3 dir="auto">Describe the solution you'd like</h3>
<p dir="auto">Some developers including myself like to create navigation elements, say for a header component, directly from the router.confg. Everything is already populated in the router config (including custom data and access via a RouteGuard). When using static routes I would normally do something like the following.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    this.items = this.router.config
      .find((route: Route) =&gt; {
        return route.path === this.routePath
      })
      ?.children
      .filter((route: Route) =&gt; {
        return route.data != null 
      })
      .map((route: Route, index) =&gt; {
        return {
          path: &quot;/&quot; + this.routePath + &quot;/&quot; + route.path,
          icon: route.data.icon,
          label: route.data.label
        }
      });"><pre class="notranslate"><code class="notranslate">    this.items = this.router.config
      .find((route: Route) =&gt; {
        return route.path === this.routePath
      })
      ?.children
      .filter((route: Route) =&gt; {
        return route.data != null 
      })
      .map((route: Route, index) =&gt; {
        return {
          path: "/" + this.routePath + "/" + route.path,
          icon: route.data.icon,
          label: route.data.label
        }
      });
</code></pre></div>
<p dir="auto">The code above simply creates an object array called items for the children of a specific route. I am not showing all the detail but just focusing on the children array because these are static routes. The object returned can be anything the developer needs.</p>
<p dir="auto">Now when using lazy loaded routes the children array is not available because the routing data is stored in lazy loaded modules that have not been loaded yet. Several people have tried to use the private _loadedConfig property on a route but it gets ugly and you end up with something like this.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    this.buttons = (this.router.config
      .find((route: Route) =&gt; {
        return route.path === this.routePath
      }) as any)
      ?._loadedConfig
      ?.routes[0]
      ?.children
      .filter((route: Route) =&gt; {
        return route.data != null 
      })
      .map((route: Route, index: number) =&gt; {
        return {
          path: &quot;/&quot; + this.routePath + &quot;/&quot; + route.path,
          icon: route.data.icon,
          label: route.data.label,
        }
      })"><pre class="notranslate"><code class="notranslate">    this.buttons = (this.router.config
      .find((route: Route) =&gt; {
        return route.path === this.routePath
      }) as any)
      ?._loadedConfig
      ?.routes[0]
      ?.children
      .filter((route: Route) =&gt; {
        return route.data != null 
      })
      .map((route: Route, index: number) =&gt; {
        return {
          path: "/" + this.routePath + "/" + route.path,
          icon: route.data.icon,
          label: route.data.label,
        }
      })
</code></pre></div>
<p dir="auto">While this works its not ideal. The obvious issue is that the private _loadedConfig is subject to change without warning in the future because its not part of the public API and this object is not available until some point in the lifecycle that I have not been able to determine yet.</p>
<p dir="auto">Now the data that is eventually available in the _loadedConfig is exactly what developers are interested in (path, data, etc.) and it seems to be available even before the lazy modules are loaded. Given this would it be possible to present this information using the normal children array regardless if it’s a static route or a lazy loaded route? In most scenarios developers only care to have access to the route children and its less important that it’s from a static route vs. a lazy loaded route. A Boolean or enumeration could be added that would let the developer know the route static vs lazy if that is important.</p>
<p dir="auto">This would mean any code designed to work with the router, config, and children would work with static or lazy loaded routes. The project could start with standard static routes and then later be reconfigured to use lazy routes and any code already in place that leverages the router config would continue to work.</p>
<p dir="auto">One additional thought would be at webpack/compile time Angular would have access to all the routes regardless if they are static or lazy. Maybe some metadata can be derived from this and used to populate the routes children information at runtime.</p>
<p dir="auto">I know it’s a long shot, but I wanted to suggest the general idea.</p>
<p dir="auto">Thanks,<br>
Eric</p>