質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Angular

Angularは、JavaScriptフレームワークです。AngularJSの後継であり、TypeScriptベースで実装されています。機能ごとに実装を分けやすく、コードの見通しが良いコンポーネント指向です。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

解決済

1回答

4939閲覧

Angular 画面遷移時の値受け渡し値について

propg

総合スコア113

Angular

Angularは、JavaScriptフレームワークです。AngularJSの後継であり、TypeScriptベースで実装されています。機能ごとに実装を分けやすく、コードの見通しが良いコンポーネント指向です。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

0クリップ

投稿2018/11/20 09:32

編集2018/11/21 01:18

Angular6で画面遷移時の値の受け渡しについて実装しています。

Serviceクラスを使って、遷移元から遷移先に値を受け渡します。
値は受け取りできているようです。
受け取った値を、コンポーネントの変数にセットして、その値をページに表示しようとしたところ、undefinedになっています。

ts内で取得したタイミングで、値を確認した際には取得した値が表示されます。

遷移先の受け取りロジック

typescript

1 2@Component({ 3 selector: 'app-test', 4 templateUrl: './test.component.html', 5 styleUrls: ['./test.component.scss'] 6}) 7export class TestComponent implements OnInit { 8 bbbb; 9 10 private _aaaa: any; 11 @Output('aaaa') 12 public get aaaa(): any { 13 return this._aaaa; 14 } 15 public set aaaa(v: any) { 16 if (v) { 17 this._aaaa = v; 18 console.log('aaaa', v); 19 } 20 } 21 22 constructor(private screenTransition: ScreenTransitionService) { 23 24 this.screenTransition.getMsgToChild().subscribe(event => { 25 this.aaaa = event; 26 console.log('this.aaaa', this.aaaa); 27 28 this.patientAttribute = event as VKanjaKensa; 29 }); 30 31 this.bbbb = 'テストデータ'; 32 }
  • subscribe内、console.logには受け取った値が正しく出力される。
  • テンプレートhtmlで{{aaaa}}としたところには、何も表示されない
  • buttonを置いて、(click)イベントで変数の値を表示するとthis.aaaaの値はundefined
  • subscribe外で、this.aaaa = '12345'などとした値は、正常に表示される

subscribe内で参照しているthis.aaaaと、Componentクラスで定義しているthis.aaaaが別領域のものなのかなと思いますが、エラーになるわけではなく原因不明です。
subscribeの理解不足ですが、なにか書き方に問題があるでしょうか?

ScreenTransitionServiceの実装

typescript

1import { Injectable } from '@angular/core'; 2import { Subject } from 'rxjs/Subject'; 3import { Observable } from 'rxjs'; 4 5@Injectable({ 6 providedIn: 'root' 7}) 8export class ScreenTransitionService { 9 constructor() {} 10 11 private toParentDataSource = new Subject<any>(); 12 private toChildDataSource = new Subject<any>(); 13 14 sendMsgToParent(msg: any) { 15 this.toParentDataSource.next(msg); 16 } 17 18 getMsgToParent(): Observable<any> { 19 return this.toParentDataSource.asObservable(); 20 } 21 getMsgToChild(): Observable<any> { 22 return this.toChildDataSource.asObservable(); 23 } 24 25 sendMsgToChild(msg: any) { 26 this.toChildDataSource.next(msg); 27 } 28}

テンプレートHTML

html

1<div>aaaa={{aaaa}}</div> 2<div>bbbb={{bbbb}}</div>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

コメントに関してご回答します。

DIするサービスの変数はそれぞれのコンポーネントで、共有できるという解釈でいいものでしょうか?

基本的にその解釈で正しいです。ドキュメントを見ると、「CLIで生成されたアプリケーションでは、モジュールは事前ロードされプロバイダー(service)は全モジュールで利用可能となる」と有ります。そして「Angularルーターがモジュールを遅延ロードすると、新しいインジェクターが作成されます」とあり、遅延ロードしたComponentでは別インスタンスとなり共有できないものと解釈できます。

https://angular.jp/guide/providers

angularではページ部品をcomponentとすることでcomponentを組み合わせてページを作成したり、他ページで再利用することが可能です。そしてcomponent間のデータ受け渡しやイベントの通知にserviceをDIしてsubscribeを使用する方法が有ります。また、DB連動のためにrestサービスを使用する場合なども、serviceとして実装していれば、メソッドを各componentで共通利用できます。単にデータ共有する場合ではsubscribeを利用する必要は有りませんが、自componentで発生したイベントを他componentに通知したい時にはsubscribeを利用することになります。


実際に画面遷移するコードを書いて試してみました。結果、Routerを使用した画面遷移を行えばserviceは共有でき、serviceに保持用のメンバを配置してget/setterを使えばページ間のデータ受け渡しが出来ました。また、subscribeではデータ送信時(next)に受信側のComponentのインスタンスが不在なのでデータは受け取れないようです。ご参考までに確認したコードを記載します。

app.module.ts

javascript

1import { BrowserModule } from '@angular/platform-browser'; 2import { NgModule } from '@angular/core'; 3 4import { AppRoutingModule } from './app-routing.module'; 5import { AppComponent } from './app.component'; 6 7import { SendComponent } from './send/send.component'; 8import { ReceiveComponent } from './receive/receive.component'; 9import {TestService} from './test.service' 10 11@NgModule({ 12 declarations: [ 13 AppComponent, 14 SendComponent, 15 ReceiveComponent 16 ], 17 imports: [ 18 BrowserModule, 19 AppRoutingModule 20 ], 21 providers: [TestService], 22 bootstrap: [AppComponent] 23}) 24export class AppModule { } 25

app-routing.module.ts

javascript

1import { NgModule } from '@angular/core'; 2import { Routes, RouterModule } from '@angular/router'; 3 4import { SendComponent } from './send/send.component'; 5import { ReceiveComponent } from './receive/receive.component'; 6 7const routes: Routes = [ 8 {path:'send',component:SendComponent}, 9 {path:'receive',component:ReceiveComponent} 10]; 11 12@NgModule({ 13 imports: [RouterModule.forRoot(routes)], 14 exports: [RouterModule] 15}) 16export class AppRoutingModule { }

app.component.ts

javascript

1import { Component,OnInit } from '@angular/core'; 2import { Router } from '@angular/router'; 3 4@Component({ 5 selector: 'app-root', 6 templateUrl: './app.component.html', 7 styleUrls: ['./app.component.css'] 8}) 9export class AppComponent implements OnInit{ 10 title = 'tera01'; 11 12 constructor(private router:Router) { } 13 14 ngOnInit(){ 15 this.router.navigate(['send']); 16 } 17 18} 19

app.component.html

html

1<router-outlet></router-outlet>

send.component.ts

javascript

1import { Component, OnInit } from '@angular/core'; 2import { Router } from '@angular/router'; 3 4import {TestService} from '../test.service' 5 6@Component({ 7 selector: 'app-send', 8 templateUrl: './send.component.html', 9 styleUrls: ['./send.component.css'] 10}) 11export class SendComponent implements OnInit { 12 13 constructor(private service:TestService,private router:Router) { } 14 15 ngOnInit() { 16 } 17 18 onClick(){ 19 this.service.setMessage("from SendComponent"); 20 this.router.navigate(['receive']); 21 } 22 23 24} 25

receive.component.ts

javascript

1import { Component, OnInit } from '@angular/core'; 2 3import {TestService} from '../test.service' 4 5@Component({ 6 selector: 'app-receive', 7 templateUrl: './receive.component.html', 8 styleUrls: ['./receive.component.css'] 9}) 10export class ReceiveComponent implements OnInit { 11 12 msg:any; 13 14 constructor(private service:TestService) { 15 } 16 17 ngOnInit() { 18 this.msg = this.service.getMessage(); 19 } 20 21} 22

test.service.ts

javascript

1import { Injectable } from '@angular/core'; 2 3@Injectable({ 4 providedIn: 'root' 5}) 6 7export class TestService { 8 9 private message:string; 10 11 getMessage():string{ 12 return this.message; 13 } 14 15 setMessage(msg:string){ 16 this.message=msg; 17 } 18 19} 20

console.logの表示が正しいのであれば、subscribeのcallbackは出来ていると思えます。そうなるとComponent(class)とtemplate(html)のマッピングがどこかおかしいのではないでしょうか。

@Componentの情報は記載できますか?

aaaa以外に変数を定義し、templateと双方向バインドが出来ているか確認できますか?

<追記>
this.aaaa = event; を this.aaaa = "test";と変えてみてブラウザ表示されるのであればtemplateとのマッピングは解決している(領域は共有している)と思います。bbbbでも成功しているようですし。そうなると引数で渡ってくるeventの内容(もしくは型)に表示できない要素があるのではと推測します。
aaaa:anyと宣言してもNGだったでしょうか?

<追記>
すみません、初めから勘違いをしていたようです。画面遷移しているのですね(読み落としておりました)。SPAデザインと思いこんでいました。遷移先画面ではserviceをinjectしても別インスタンスになるものと思われます(試していないのですが恐らくそうでしょう)そうなると遷移前画面からのsubscribは読めないですね。前述の「領域は共有している」は撤回いたします。遷移先ページには他手段で値を渡す必要があると思います。
「angular 画面遷移 データ受け渡し」で検索されてはどうでしょうか。

投稿2018/11/20 11:18

編集2018/11/22 09:19
BlueMoon

総合スコア1339

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

propg

2018/11/21 01:21

回答有り難うございます。 @Componentにはほとんど記載していませんが、本文中に追記しました bbbbという変数を定義し、Observableを経由せずに直接設定した値は正常にバインドされています。 また、試しに、 Observable.interval(1000).subscribe(msg => { this.aaaa = msg; }); という実装をしてみたところ、html中のaaaaは更新され続けました。
BlueMoon

2018/11/21 01:35

情報の更新を有難うございます。aaaaの宣言がプライベートに変わっていますが、publicのままでも同様ということでしょうか。chromeに表示させてみてdevelopertoolのconsole上に何らかのエラー表示は出ていませんか? そうなるとちょっとお手上げですなのですが。
propg

2018/11/21 04:19

aaaaはプロパティにしていますので、publicです。 public aaaa: any;としても同様でした。 返信に書いたObservable.interval(1000).subscribe(msg... でaaaaの値がhtmlに表示されていることから、変数宣言に問題はないと考えています。 となると怪しいのは、Serviceの作りに問題があるんじゃないかと思うのですが、今の所Rxの仕組みがあまり理解できていないため、どうすべきかわかっていません。 ちなみに、Serviceにpublic変数を追加し、遷移元で値を設定したものは、遷移先でもそのまま値を取得することができました。(html上にも表示されました) Service経由でのデータやり取りの場合、subscribeを利用することは必須なのでしょうか?
BlueMoon

2018/11/21 09:01

Routerを使用した画面遷移で、subscribeを使用しない方法で検証してみましたので回答をご覧ください。画面遷移においては、subscribeではデータが渡せないようです。
propg

2018/11/22 05:48

検証までしていただきましてありがとうございます。 こちらでもservice内の変数での持ち回りができることは確認できています。 ただ、もともとこのやり方でやってみたのは、どこかのサイトで、ログイン情報の持ち回り方として紹介されてたものです。 subscribeは非同期処理に使用するもので、httpでは必須だと思いますが、すでに取得済みの値に対しての変数の持ち回りについて、わざわざsubscribeを経由する意図が不明でした。 DIするサービスの変数はそれぞれのコンポーネントで、共有できるという解釈でいいものでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問