NativeScript / nativescript-angular

Integrating NativeScript with Angular
http://docs.nativescript.org/angular/tutorial/ng-chapter-0
Apache License 2.0
1.21k stars 241 forks source link

Trying to add naviation to `WebView` #470

Closed tsonevn closed 8 years ago

tsonevn commented 8 years ago

From @okmttdhr on September 26, 2016 0:4

Please, provide the details below:

Did you verify this is a real problem by searching Stack Overflow and the other open issues in this repo?

Yes

Which platform(s) does your issue occur on?

iOS

Please provide the following version numbers that your issue occurs with:

I'm trying to add naviation to WebView with Angular. Here's 3 components; webview-page webview-navigation and navigation-text.

import { Component, ElementRef, ViewChild } from "@angular/core"; 

@Component({
  selector: "webview-page",
  template: `
    <DockLayout stretchLastChild="true">
      <StackLayout dock="bottom">
        <webview-navigation [webview]="webview"></webview-navigation>
      </StackLayout>
      <GridLayout dock="top" columns="*" rows="*">
        <WebView #webview src="http://example.com" row="0" col="0"></WebView>
      </GridLayout>
    </DockLayout>
  `
})
export class WebviewPage {
  @ViewChild("webview") webview: ElementRef;
}

I want to change the color of text to the active or disabled color after WebView.loadFinishedEvent (It should be the active color if you can goBack or goForward, if not, should be disabled). But nothing changes if the WebView page transitions happen.

import { Component, Input } from "@angular/core";
import { WebView } from "ui/web-view";

const activeColor = "#000000";
const disabledColor = "#dddddd";

@Component({
  selector: "webview-navigation",
  template: `
    <StackLayout orientation="horizontal">
        <navigation-text (tap)="goBack()" name="back" [color]="goBackIconColor"></navigation-text>
        <navigation-text (tap)="goForward()" name="forward" [color]="goForwardIconColor"></navigation-text>
    </StackLayout>
  `
})
export class WebviewNavigation {
  @Input() webview: WebView;
  private goBackColor: string = disabledColor;
  private goForwardColor: string = disabledColor;
  ngOnInit() {
    this.webview.on(WebView.loadFinishedEvent, () => {
      this.updateIconColor();
    }, this);
  }
  updateIconColor() {
    this.goBackColor = this.webview.canGoBack ? activeColor : disabledColor;
    this.goForwardColor = this.webview.canGoForward ? activeColor : disabledColor;
  }
  goBack() {
    this.webview.goBack();
  }
  goForward() {
    this.webview.goForward();
  }
}
// this is a very simple component but actually it's more complex, so I need to create this component
import { Component, Input, Output, EventEmitter } from "@angular/core";

@Component({
  selector: "navigation-text",
  template: `
    <Label (tap)="onTap()" [text]="name" [color]="color"></Label>
  `
})
export class NavigationText {
  @Input() name: string;
  @Input() color: string;
  @Output("tap") tap = new EventEmitter();
  onTap() {
    this.tap.emit({});
  }
}

What is the problem? Or anyone implemented the navigation to WebView?? I'll appreciate your help.

Copied from original issue: NativeScript/NativeScript#2797

tsonevn commented 8 years ago

Hi @okmttdhr.

You could review this sample code, where has been shown how you could use WebView and how to create simple navigation bar for this component , while using NativeScript Angular2 template. In the example has been also shown how to handle WebView loadFinishedEvent in your project.

I hope this will help.

okmttdhr commented 8 years ago

@tsonevn Thank you for your reply.

Yes, I am using loadFinishedEvent as this sample code does.

And the callback function has been called with every webview page transitions, but this.goBackColor and this.goForwardColor couldn't be binded to child component (=NavigationText component)


[update]

Colors have changed (just for a test. not corresponding to a webview transition) if I changed WebviewNavigation component to this;

import { Component, Input } from "@angular/core";
import { WebView } from "ui/web-view";

const activeColor = "#000000";
const disabledColor = "#dddddd";

@Component({
  selector: "webview-navigation",
  template: `
    <StackLayout orientation="horizontal">
        <navigation-text (tap)="goBack()" name="back" [color]="goBackColor"></navigation-text>
        <navigation-text (tap)="goForward()" name="forward" [color]="goForwardColor"></navigation-text>
    </StackLayout>
  `
})
export class WebviewNavigation {
  @Input() webview: WebView;
  private goBackColor: string = disabledColor;
  private goForwardColor: string = disabledColor;
  ngOnInit() {
    this.updateIconColor(); // just adding colors here for a test. not corresponding to a webview transition
  }
  updateIconColor() {
    this.goBackColor = activeColor;
    this.goForwardColor = activeColor;
  }
  goBack() {
    this.webview.goBack();
  }
  goForward() {
    this.webview.goForward();
  }
}

So, I think there are some problems in the callback function of this.webview.on().

tsonevn commented 8 years ago

Hi @okmttdhr, perhaps the problem is due to the fact that you set for the color property of the first component goBackIconColor instead of goBackColor and for the second one goForwardIconColor instead of goForwardColor. Regarding to that, could you verify whether this is causing the problem or it is something else. Example:

 <navigation-text (tap)="goBack()" name="back" [color]="goBackColor"></navigation-text>
 <navigation-text (tap)="goForward()" name="forward" [color]="goForwardColor "></navigation-text>

Regards, @tsonevn

okmttdhr commented 8 years ago

@tsonevn

the color property of the first component goBackIconColor instead of goBackColor and for the second one goForwardIconColor instead of goForwardColor

I am sorry... My original code is little bit different, so I mistyped...

Regarding to that, could you verify whether this is causing the problem or it is something else.

But it didn't work even if I fixed the property name. It always happens when I change the property in the callback of this.webview.on(WebView.loadFinishedEvent, () => {/*here*/}), it's fine in the other places.

okmttdhr commented 8 years ago

I found the solution.

Firstly, I needed to access nativeElement of Angular 2. Secondly, I added ChangeDetectorRef.detectChanges() to detect the property changes (this is the solution for that the property changes couldn't detected in the callback of WebView.on()).

http://stackoverflow.com/questions/35105374/how-to-force-a-components-re-rendering-in-angular-2 https://angular.io/docs/ts/latest/api/core/index/ChangeDetectorRef-class.html#!#detectChanges-anchor

import { Component, Input, ElementRef, ChangeDetectorRef } from "@angular/core";
import { WebView } from "ui/web-view";

const activeColor = "#000000";
const disabledColor = "#dddddd";

@Component({
  selector: "webview-navigation",
  template: `
    <StackLayout orientation="horizontal">
        <navigation-text (tap)="goBack()" name="back" [color]="goBackColor"></navigation-text>
        <navigation-text (tap)="goForward()" name="forward" [color]="goForwardColor"></navigation-text>
    </StackLayout>
  `
})
export class WebviewNavigation {
  @Input("webviewRef") webviewRef: ElementRef;
  private webview: WebView;
  private goBackColor: string = disabledColor;
  private goForwardColor: string = disabledColor;
  constructor(private ref: ChangeDetectorRef) {}
  ngOnInit() {
    this.webview = this.webviewRef.nativeElement; // access nativeElement
    this.webview.on(WebView.loadFinishedEvent, () => {
      this.updateIconColor();
    }, this);
  }
  updateIconColor() {
    this.goBackColor = this.webview.canGoBack ? activeColor : disabledColor;
    this.goForwardColor = this.webview.canGoForward ? activeColor : disabledColor;
    this.ref.detectChanges(); // update components.
  }
  goBack() {
    this.webview.goBack();
  }
  goForward() {
    this.webview.goForward();
  }
}

I am sorry for bothering and thank you for replying.