[解決済み] Angular "未定義のプロパティ 'subscribe' を読み取ることができません".
2022-01-29 17:05:39
質問
質問を始める前に、私はすでに大規模な調査を行いましたが、なぜこのエラーが発生するのか、解決策(説明)を見つけることができなかったことをお知らせしたいと思います。
また、私はAngularの全くの初心者であり、どのように動作するかを学び始めたばかりであることに留意してください。
そこで、私が抱えている問題は、この質問のタイトルに入力した内容です。
Udemyで購入したコースを元に、Firebaseを使ってログインシステムを構築しようとしています。
私が使用しているコードは以下の通りです。
auth.service.ts
import {Injectable} from '@angular/core';
import * as firebase from 'firebase';
@Injectable ()
export class AuthService {
token: string;
// ...
singInUser ( email: string, password: string ) {
// login process here ...
}
// Responsible to retrieve the authenticated user token
getToken () {
return firebase
.auth ()
.currentUser
.getIdToken ();
}
}
data-storage.service.ts
// ... Dependencies here
@Injectable ()
export class DataStorageService {
private recipeEndPoint: string = 'https://my-unique-id.firebaseio.com/recipes.json';
private recipeSubscription: Observable<any> = new Observable();
constructor ( private http: Http,
private recipes: RecipeService,
private authService: AuthService ) {}
// other functionality ...
getRecipes () {
const token = this.authService.getToken ();
token.then (
( token: string ) => {
this.recipeSubscription = this.http.get ( this.recipeEndPoint + '?auth=' + token ).map (
( data: Response ) => {
return data.json ();
}
);
// THIS PARTICULAR CODE WORKS AS EXPECTED
// WITH NO ISSUES
this.recipeSubscription.subscribe (
( data: Response ) => {
console.log ( 'Data response: ', data );
},
( error ) => {
console.log ( 'Error: ' + error );
}
)
}
);
// This is supposed to return an Observable to the caller
return this.recipeSubscription;
}
}
header.component.ts
// Dependencies here ...
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
constructor(private dataStorage: DataStorageService, private recipeService: RecipeService) { }
// Other Code Here ...
onFetchData() {
let recipeSubscription = this.dataStorage.getRecipes();
// THIS RETURNS TRUE
console.log(recipeSubscription instanceof Observable);
// THIS LINE THEN RETURNS THE MESSAGE:
// ERROR TypeError: Cannot read property 'subscribe' of undefined
recipeSubscription.subscribe();
// IF I COMMENT OUT THE PREVIOUS LINE
setTimeout(
() => {
// THIS RETURNS TRUE
console.log(recipeSubscription instanceof Observable);
},
500
);
setTimeout(
() => {
// AS WELL THIS ONE RETURNS TRUE
console.log(recipeSubscription instanceof Observable);
},
1000
);
setTimeout(
() => {
// AS WELL THIS ONE RETURNS TRUE
console.log(recipeSubscription instanceof Observable);
},
1500
);
}
}
というわけで、残念ながらこのコードの何が問題なのかがわかりません。どなたか、私が何か間違ったことをしたのを見付けられる方はいらっしゃいますか?
注 スニペットを読みやすくするために、私のコードの一部を削除しました。もし、他の部分が必要な場合は、遠慮なく私に尋ねてください。
アップデイト#1
のように見えます。
header.component.html
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">Logo Here</div>
<div class="navbar-default">
<ul class="nav navbar-nav">
<!-- Left Navigation Options -->
</ul>
<ul class="nav navbar-nav navbar-right">
<!-- Right Navigation Options -->
<li class="dropdown" appDropdown>
<a routerLink="/" class="dropdown-toggle" role="button">Manage <span class="caret"></span></a>
<ul class="dropdown-menu">
<li>
<a style="cursor: pointer;" (click)="onSaveData()">Save Data</a>
</li>
<li>
<!-- Here is where I call the onFetchData method -->
<a style="cursor: pointer;" (click)="onFetchData()">Fetch Data</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
解決方法は?
問題は、コードの実行順序にあるようです。
getRecipes()
メソッドを使用します。
// Numbers indicate the execution order
getRecipes () {
const token = this.authService.getToken ();
// 1. You call a promise, which will take a while to execute...
token.then (
( token: string ) => {
// 3. Finally, this bit gets executed, but only when the promise resolves.
this.recipeSubscription = ...
}
);
// 2. Then, you return a variable that hasn't been assigned yet,
// due to the async nature of the promise.
return this.recipeSubscription;
}
これを解決するのは、あなたの
getRecipes ()
メソッドは SUBSCRIBE すべきではない(SHOULD NOT)。それは
PromiseかObservableのどちらかを返します。
.
このようなものです。
getRecipes() {
// Convert the initial promise into an observable
// so can you use operators like map(), mergeMap()... to transform it.
const tokenObs = Observable.fromPromise(this.authService.getToken());
// Merge the token observable into an HTTP observable
// and return the JSON data from the response.
return tokenObs
.mergeMap(token => this.http.get('XXX?auth=' + token))
.map(resp => resp.json());
}
では、呼び出し側のコードである
HeaderComponent
は次のようになります。
const recipeObs = this.dataStorage.getRecipes();
recipesObs.subcribe(jsonData => {
// Use the JSON data from the HTTP response
});
いくつかの発言。
- コード内で使用するRxJS演算子を明示的にインポートする必要があります。もし、私の例に従うなら、以下のimportを最初に追加する必要があります。
import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
-
observableを作成するメソッドでは、決してsubscribeしてはいけません。あなたの場合、サブスクライブする場所は
getRecipes()
. サブスクライブは必ず、可能な限り最後のタイミングで行ってください。同じobservableに何度もサブスクライブすることができますが、それぞれのサブスクリプションがobservableを再実行することに注意してください(httpリクエストの場合、それはリクエストを複数回実行することを意味します;理想的ではないですが・・・)。 -
変数に呼び出すのは良いアイデアではありません。
recipeSubscription
を含んでいるのでObservable
ではなくSubscription
. サブスクリプションとはsubscribe()
を返します。言い換えればconst subscription = observable.subscribe()
. - Firebase SDKを直接使っているようですね。を意識しているのでしょうか? AngularFire ライブラリ ?
関連
-
[解決済み] @viewChildが機能しない - プロパティnativeElementがundefinedで読み込めない
-
[解決済み] Angular 2の@ViewChildアノテーションがundefinedを返す
-
[解決済み] "rxjs" observable.throw は関数ではありません - Angular4
-
[解決済み] Angular2の素材ダイアログに問題あり - @NgModule.entryComponentsに追加しましたか?
-
[解決済み] ngModel' は 'input' の既知のプロパティではないため、バインドできません。
-
[解決済み] formGroup' は 'form' の既知のプロパティではないため、バインドできません。
-
[解決済み] Angular HTMLバインディング
-
[解決済み] TypeScript で `window` に新しいプロパティを明示的に設定するにはどうすればよいですか?
-
[解決済み] Angular:*ngClassを使った条件付きクラス
-
[解決済み] モジュール "@angular-devkit/build-angular" が見つかりませんでした。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】angular 4アプリにReactiveFormsModuleを追加すると、NgControl用のプロバイダがないエラーが発生する。
-
[解決済み】ngサーブが機能しない
-
[解決済み] Typescript - コードが TS1128: Declaration or Statement expected というエラーでビルドに失敗するが、コードを提供すると期待通りに実行される。
-
[解決済み] Electron - ローカルリソースのロードが許可されていません
-
[解決済み] Uncaught (in promise): Ionic 2でcordova_not_available。
-
[解決済み] ionInputとionChangeで有意差あり
-
[解決済み] Angular 2の「コンポーネント」は既知の要素ではありません。
-
[解決済み] Angularアプリのシンタックスエラー。予期しないトークン <
-
[解決済み] ローカルホストが私のアンギュラーアプリに対して無効な応答を送信しました。
-
[解決済み] Angular 6でmouseoverとmouseoutを使用する方法