Skip to content

feat: enable nesting named page router outlets #1556

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

Merged
merged 10 commits into from
Oct 25, 2018

Conversation

ADjenkov
Copy link
Contributor

@ADjenkov ADjenkov commented Oct 15, 2018

TO DO: Add description
Resolve: #1351

@ADjenkov ADjenkov self-assigned this Oct 15, 2018
@ghost ghost added the in progress label Oct 15, 2018
@ADjenkov ADjenkov force-pushed the djenkov/nested-outlets branch from c840df2 to af4a15d Compare October 17, 2018 11:10
@ADjenkov ADjenkov force-pushed the djenkov/nested-outlets branch 2 times, most recently from d3250ec to 7d68733 Compare October 18, 2018 10:27
@ADjenkov
Copy link
Contributor Author

test branch_testsappng#djenkov/nested-outlets sdk_ng

@@ -342,10 +361,27 @@ export class PageRouterOutlet implements OnDestroy { // tslint:disable-line:dire
}

private markActivatedRoute(activatedRoute: ActivatedRoute) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comments on what this method does

@@ -149,16 +150,17 @@ export class PageRouterOutlet implements OnDestroy { // tslint:disable-line:dire
private parentContexts: ChildrenOutletContexts,
private location: ViewContainerRef,
@Attribute("name") name: string,
@Attribute("isNSEmptyOutlet") isNSEmptyOutlet: boolean,
Copy link
Contributor

@vakrilov vakrilov Oct 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property can be named isEmptyOutlet -> it is already inside a PageRouterOutlet class that is NS-specific.
Also you can inject and define it in the same time

Suggested change
@Attribute("isNSEmptyOutlet") isNSEmptyOutlet: boolean,
@Attribute("isNSEmptyOutlet") private isEmptyOutlet: boolean,

@@ -81,7 +82,10 @@ export class ModalDialogService {
const componentContainer = moduleRef || viewContainerRef;
const resolver = componentContainer.injector.get(ComponentFactoryResolver);

const frame = parentView.page && parentView.page.frame;
let frame = parentView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment about the scenario where parentView is a Frame? (it seems previously there wasn't such scenario?)

@@ -81,7 +82,10 @@ export class ModalDialogService {
const componentContainer = moduleRef || viewContainerRef;
const resolver = componentContainer.injector.get(ComponentFactoryResolver);

const frame = parentView.page && parentView.page.frame;
let frame = parentView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment about the scenario where parentView is a Frame? (it seems previously there wasn't such scenario?)

if (url !== tree.toString()) {
const urlSerializer = new DefaultUrlSerializer();
const stateUrlTree: UrlTree = urlSerializer.parse(url);
const rootOutlets = stateUrlTree.root.children;

Object.keys(rootOutlets).forEach(outletName => {
const topState = this.peekState(outletName);
const outlet = this.findOutletByKey(outletName);
const topState = outlet.peekState();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

topState is not guarded for null

} else {
const queue = [];
queue.push(urlTreeRoot);
let currentTree = queue.shift();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const queue = [];
let currentTree = urlTreeRoot;

// tslint:disable-next-line:component-selector
selector: "ns-empty-outlet",
moduleId: module.id,
template: "<page-router-outlet isNSEmptyOutlet='true'></page-router-outlet>"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If isNSEmptyOutlet is renamed this should be renamed as well.

@@ -81,7 +82,10 @@ export class ModalDialogService {
const componentContainer = moduleRef || viewContainerRef;
const resolver = componentContainer.injector.get(ComponentFactoryResolver);

const frame = parentView.page && parentView.page.frame;
let frame = parentView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment about the scenario where parentView is a Frame? (it seems previously there wasn't such scenario?)

@@ -52,19 +79,21 @@ export class NSLocationStrategy extends LocationStrategy {
return "/";
}

const state = this.peekState(this.currentOutlet);
const state = this.currentOutlet && this.currentOutlet.peekState();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for this.currentOutlet to be null when this.currentUrlTree is not null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We set currentUrlTree inside pushStateInternal where all incoming urls are transformed into outlets . There will be always at least 1 Outlet set as currentOutlet . The otherwise should be possible only if pushState() is called from Angular with empty url param.

this.currentUrlTree = urlSerializer.parse(url);
const urlTreeRoot = this.currentUrlTree.root;

if (!Object.keys(urlTreeRoot.children).length) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reduce indentation of the main case instead of:

if (!Object.keys(urlTreeRoot.children).length) {

} else {
    // else clause statements go here...
}

Use:

if (!Object.keys(urlTreeRoot.children).length) {
    // ...
    return;
}

// else clause statements go here...

} else {
tree.root.children[this.currentOutlet] = state.segmentGroup;
} else if (changedOutlet) {
// tslint:disable-next-line:max-line-length
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably comment is unnecessary at this point.

componentView.closeModal();
this.location.back();
this.location._finishCloseModalNavigation();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename to _closeModalNavigation?

return null;
}

containsLastState(stateUrl: string): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe containsTopState?

isPageNavigationBack: boolean;
outletKeys: Array<string>;
pathByOutlets: string;
statesByOutlet: Array<LocationState> = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to states?

segmentGroup = segmentGroup.children[currentPath];
} else {
segmentGroup = null;
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain this with a comment

@SvetoslavTsenov
Copy link
Contributor

test nested-router-tab-view#djenkov/nested-outlets

modalNavigationDepth: number;
parent: Outlet;
isPageNavigationBack: boolean;
outletKeys: Array<string>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Reminder] As discussed it would be useful to add a comment why Outlet can have multiple (two) keys.

}
}

queue.push(currentTree.children[outletName]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Reminder] queue.push(currentSegmentGroup) for clarity.


while (segmentGroup) {
const url = segmentGroup.toString();
fullPath = fullPath ? (url ? url + "/" : url) + fullPath : url;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one-liner is concise but that also makes it unnecessarily complex to understand.

private updateSegmentGroup(rootNode, oldSegmentGroup: UrlSegmentGroup, newSegmentGroup: UrlSegmentGroup) {
const queue = [];
queue.push(rootNode);
let currentTree = queue.shift();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const queue = [];
let currentTree = rootNode;

@ghost ghost assigned SvetoslavTsenov Oct 22, 2018
@SvetoslavTsenov
Copy link
Contributor

test branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

ADjenkov and others added 6 commits October 23, 2018 13:45
feat(location-strategy): refactor location strategy to support nested p-r-o

feat(reuse-strategy): refactor reuse strategy to support nested p-r-o

chore(frame-service): cleanup FrameService from unused methods

feat(router-extensions): extend back() to handle specific outlets by relative route

feat(location-strategy): rework location strategy to support simultaneously outlets back navigation

chore(e2e-tests): extend nested tabs test app with 'split view'

chore: mark states with the current parent route path

chore: add parent outlet to Outlet

chore(router-extensions): prevent back navigation of outlet that already navigating back

chore(reuse-strategy): extend cache key with parent route state string (unique)

fix(router-extensions): fix back navigation when only relative route provided. Should find and back in the current outlet

chore(e2e-tests): extend nested-router-tab-view app with tests

chore(location-strategy): rework location strategy to store outlets by their parent path and current outlet name

chore(reuse-strategy): child components should not be reteached when parent is detached

chore(e2e-tests): extend e2e tests

chore(reuse-strategy): modify shouldDetach to mark parent outlet

chore(location-strategy): Modify getRouteFullPath method

chore(p-r-o): mark all activated routes child routes that have coresponding outlet

chore(router-extensions): find top activated route  node for outlet when going back

chore(location-strategy): modify getRouteFullPath to generates proper url path

chore(p-r-o): find the top activated route for outlet inside activateWith method

chore(e2e-tests): extend nested tab view app with lazy loaded home module

feat(router-extensions): extend canGoBack() to handle specific outlets by relative route

e2e tests added

feat(modal-views): remove the back navigation when destroying modal views with p-r-o

Introduce modalNavigationDepth to mark all p-r-o , along with their states, shown as modals.

chore(e2e-modal-navigation): modify goBack to back in the current ActivatedRoute

feat(modal-views): create outlet for any p-r-o displayed as modal view (even if it's 'primary')

feat: introduce NSEmptyOutletComponent to support nested named lazy loaded modules

feat(page-router-outlet): support named lazy loaded outlet

Allow Outlet to be associated with more than one p-r-o (NSEmptyOutlet)
@ADjenkov ADjenkov force-pushed the djenkov/nested-outlets branch from b9329d2 to 37f9aa4 Compare October 23, 2018 10:48
@ADjenkov
Copy link
Contributor Author

test nativescript_ng_cosmos branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

1 similar comment
@ADjenkov
Copy link
Contributor Author

test nativescript_ng_cosmos branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

@ADjenkov ADjenkov force-pushed the djenkov/nested-outlets branch from 452cb8f to 7259fc1 Compare October 23, 2018 14:41
@ADjenkov
Copy link
Contributor Author

test nativescript_ng_cosmos branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

@SvetoslavTsenov
Copy link
Contributor

test nativescript_ng_cosmos branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets nativescript_ng_cosmos_api28 nativescript_ng_cosmos_ios12

@SvetoslavTsenov
Copy link
Contributor

test nativescript_ng_cosmos branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets nativescript_ng_cosmos_api28 nativescript_ng_cosmos_ios12

@SvetoslavTsenov
Copy link
Contributor

test branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

@SvetoslavTsenov
Copy link
Contributor

test branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

1 similar comment
@SvetoslavTsenov
Copy link
Contributor

test branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

@SvetoslavTsenov
Copy link
Contributor

test branch_nested-router-tab-view#djenkov/nested-outlets testsappng#djenkov/nested-outlets

@SvetoslavTsenov SvetoslavTsenov merged commit 46a0dc0 into master Oct 25, 2018
@SvetoslavTsenov SvetoslavTsenov deleted the djenkov/nested-outlets branch October 25, 2018 07:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants