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

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

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

RxJSは、Observablesを用いたリアクティブプログラミングのJavaScript向けの実装です。イベント駆動処理も含めた非同期処理を高い可読性を持って容易にコーディングできます。

Angular

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

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

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

Q&A

解決済

1回答

3130閲覧

【Angular】ComponentがServiceのデータを直接書き換えないようにしたい

octo

総合スコア17

RxJS

RxJSは、Observablesを用いたリアクティブプログラミングのJavaScript向けの実装です。イベント駆動処理も含めた非同期処理を高い可読性を持って容易にコーディングできます。

Angular

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

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

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

0グッド

1クリップ

投稿2020/05/05 08:42

前提・実現したいこと

Anguar8にて、ユーザー情報を複数のコンポーネントに提供するUserServiceと、UserServiceを利用するコンポーネントの一つ:ユーザー情報編集画面(UserEditComponent)を作成しています。
編集画面には入力欄と送信ボタンを配置し、送信ボタンをクリックするとUserServiceのユーザー情報を更新するようにしたいです。

発生している問題

編集画面の入力欄でユーザー情報を書き換えると、逐次UserServiceの内容も更新されてしまいます。
ServiceからComponentへのデータの渡し方を修正する?ことで、送信ボタンのクリックまでUserServiceの内容を書き換えない方法がないか探しています。

該当のソースコード

【user.ts】ユーザー名と年齢からなるUserクラスを定義しています。

TypeScript

1export class User{ 2 name: string; 3 age: number; 4}

【user.service.ts】UserServiceでユーザー情報を保持し、複数のコンポーネントに提供する予定です。

TypeScript

1import { Injectable } from '@angular/core'; 2import { User } from './user'; 3import { Observable, of } from 'rxjs'; 4 5@Injectable({ 6 providedIn: 'root' 7}) 8export class UserService { 9 10 user: User = { name: "Tanaka", age: 20 }; 11 getUser(): Observable<User>{ 12 return of(this.user); 13 } 14 15 updateUser(newUser: User){ 16 this.user = newUser; 17 } 18 19 //確認用 20 logServiceUser(): void{ 21 console.log(this.user); 22 } 23 24 constructor() { } 25}

【user-edit.component.ts】UserServiceから受け取ったユーザー情報をngModelを使ってInput要素にバインドし、編集画面を作成しました。
Input要素の内容を書き換えた後、Submitボタンがクリックされ(=onClick()が呼ばれ)たタイミングでUserService側の情報を更新したいのですが、実際にはInput要素を書き換えた時点でUserService側のデータも更新されてしまいます(checkServiceUser()関数を使って確認済み)。

TypeScript

1import { Component, OnInit } from '@angular/core'; 2import { User } from '../user'; 3import { UserService } from '../user.service'; 4 5@Component({ 6 selector: 'app-user-edit', 7 template: ` 8 <input type="text" [(ngModel)]="user.name"> 9 <input type="number" [(ngModel)]="user.age"> 10 <button (click)="onClick()">submit</button> 11 <button (click)="checkServiceUser()">check</button> 12 ` 13}) 14export class UserEditComponent implements OnInit { 15 16 user: User; 17 getUser(): void{ 18 this.userService.getUser() 19 .subscribe( user => this.user = user ); 20 } 21 22 onClick(){ 23 //Submitがクリックされた時点でuserServiceのデータを更新したい。 24 this.userService.updateUser(this.user); 25 } 26 checkServiceUser(){ 27 console.log("check clicked"); 28 this.userService.logServiceUser(); 29 } 30 31 constructor( private userService: UserService ) { } 32 33 ngOnInit() { 34 this.getUser(); 35 } 36 37}

考えたこと

ユーザー情報がサービスからコンポーネントに渡される際、参照渡しで渡されるため、コンポーネント側でのデータ更新が直接サービスに反映されてしまっているのではと考えています。

このままでも「サービスを使った複数コンポーネント間のデータの共有」自体は非常に簡便に行えるのですが、送信ボタンのクリック時に内容確認の処理を挟む等、不都合ある場面が生じそうだと考えます。
また、上記のソースコードはサービスのプロパティをコンポーネントが直接書き換えているように思え、サービスが自身のメソッドでこれを行うように修正の必要があると考えています。

問題意識自体に誤りがある場合(内容確認は別途バリデーションの仕組みを使うべき・別にコンポーネントがサービスのデータを書き換えても問題ない、など)は恐縮ですが、ご指摘いただければ幸いです。

補足情報(FW/ツールのバージョンなど)

Angular: 8.2.14
Node: 12.14.0

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは。
お気づきのようにオブジェクトが参照渡しであるがゆえの事象です。
オブジェクトを生成してメンバをコピーしてはどうでしょうか。

TypeScript

1 user: User = new User(); 2 3 getUser(): void{ 4 5 u:User; 6 7 this.userService.getUser() 8 .subscribe( user => u.user = user ); 9 10 user.name = u.name.concat(); 11 user.age = u.age; 12 13 }

※未検証なコードです。

オブジェクトのコピーには lodashユーティリティのcloneDeepメソッドを使用する方法が有ります。ユーティリティはnpmでインストールする必要がありますが。

javascriptでlodashを使ってディープコピーを簡単に行う

ご参考までに。

投稿2020/05/06 22:46

BlueMoon

総合スコア1339

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

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

octo

2020/05/31 07:16

ありがとうございます! 必要に応じてlodashの導入も試してみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問