AngularJSにシンプルなアプリがあります。 AJAXリクエストが行われたときにメッセージを動的に表示したい。残念ながら、常に非表示の状態であり、理由を理解できない。
HTML:
<div ng-show="message">
<h2>show</h2>
</div>
<div ng-hide="!message">
<h2>Hide</h2>
</div>
AngularJSコントローラー:
function merchantListController($scope, $http, $rootScope, $location, global) {
$http({
method: 'POST',
url: global.base_url + '/merchant/list',
}).success(function($data) {
if ($data.status === 'success') {
$scope.merchants = $data.data;
$scope.$apply(function(){
$scope.message = true;
});
}
});
}
動作しない可能性が高い理由は、merchantListControllerのスコープのmessage
プロパティを次のように上書きするのではなく、子スコープ内にnewスコーププロパティを作成するためあなたは期待していたでしょう。
// The following assignment will create a 'message' variable
// in the child scope which is a copy of the scope variable
// in parent scope - effectively breaking two-way model binding.
$scope.message = true;
これを解決するには、スコープのプロパティではなく、モデルのプロパティにby by referenceをバインドしてください。
[〜#〜] html [〜#〜]
<div ng-show="my.message">
<h2>show</h2>
</div>
<div ng-hide="!my.message">
<h2>Hide</h2>
</div>
コントローラー
function merchantListController($scope, $http, $rootScope, $location, global) {
// Initialize my model - this is important!
$scope.my = { message: false };
$http({
method: 'POST',
url: global.base_url + '/merchant/list',
}).success(function($data) {
if ($data.status === 'success') {
$scope.merchants = $data.data;
// modify the 'message' property on the model
$scope.my.message = true;
}
});
});
説明
これが機能する理由は、モデルmy
がスコープ継承ルールを使用して解決されているためです。つまり、my
が現在のスコープに存在しない場合は、親スコープでmy
が見つかるか、検索が$ rootScopeで停止するまで検索します。モデルが見つかると、message
プロパティが上書きされます。
表示/非表示のロジックが間違っています...次のように変更します。ng-hide = "message"
<div ng-show="message">
<h2>show</h2>
</div>
<div ng-hide="message">
<h2>Hide</h2>
</div>
ng-hideは非表示にするときに変数を必要とし、ng-showは表示するときに変数を必要とするため、条件ng-show = "message"&ng-hide = "!message"は同じです。
これを試してください:
<div ng-show="message">
<h2>show</h2>
</div>
<div ng-show="!message">
<h2>Hide</h2>
</div>
テストのためだけに、httpクラスを次のように変更します。
$http({
method: 'POST',
url: global.base_url + '/merchant/list',
}).success(function($data) {
$scope.message = true;
}).error(function($data) {
$scope.message = false;
});
Because you did a mistake...
ng-show="message" and ng-hide="!message" both points to the same value..
Correct it as..
<div **ng-show="message"**>
<h2>show</h2>
</div>
<div **ng-hide="message"**>
<h2>Hide</h2>
</div>
//or you can do in your way as...
<div **ng-show="message"**>
<h2>show</h2>
</div>
<div **ng-show="!message"**>
<h2>Hide</h2>
</div
それで、2歳の質問に時間を費やした後、私はここに何かを入れます。
$scope.apply()
は不要であり、おそらくapplyがすでに進行中であるというエラーを引き起こします。正しく実行している場合、この関数を呼び出すことはほとんどないか、まったく呼び出さないでください。主な用途は、サードパーティのライブラリを使用する場合で、angularは変更を監視できないか、変更を確認できないため、ダイジェストサイクルを手動でトリガーする必要があります。
変数を初期化することをお勧めします。そのため、コントローラーは次のようになります(サービスへのhttp要求も抽出し、.success()
は廃止されているため、then
を使用して応答とエラーを処理します) :
function merchantService($http) {
function post() {
return $http.get('localhost');
//Just a dummy $http request, instead of yours.
//return $http.post(global.base_url + '/merchant/list');
}
/* this is rather implicit, but if you are doing a service like this,
you can keep the functions "private" and export an object, that
contains the functions you wish to make "public" */
return {
post: post
};
}
function merchantListController($scope, merchantService) {
/* Initialize the variable, so ng-show and ng-hide
have something to work with in the beginning
rather then just being undefined. */
$scope.message = false;
// call the post from the function
merchantService.post()
.then(function (response) {
/* The first then() will hold the response
if the request was OK */
console.log(response);
$scope.merchants = response.data;
/* Since this then() will be triggered on a successful request
we are safe to say $scope.message should now be true. */
$scope.message = true;
})
.then(function (error) {
// The second one is for the failed request.
console.error(error);
});
}
var app = angular.module('myApp', []);
app.controller('merchantListController', merchantListController);
app.factory('merchantService', merchantService);
ここで動作するフィドルを見つけることができます: https://jsfiddle.net/vnjbzf3o/4/
$ scope。$ digest()関数は、$ scopeオブジェクト内のすべてのウォッチと、その子$ scopeオブジェクト(ある場合)を繰り返し処理します。 $ digest()がウォッチを反復処理するとき、各ウォッチの値関数を呼び出します。値関数によって返される値が、最後に呼び出されたときに返された値と異なる場合、そのウォッチのリスナー関数が呼び出されます。
$ digest()関数は、AngularJSが必要であると考えるたびに呼び出されます。たとえば、ボタンクリックハンドラが実行された後、またはAJAXコールが返された後(done()/ fail()コールバック関数が実行された後)。
AngularJSが$ digest()関数を呼び出さないという、まれなケースが発生する場合があります。通常、データバインディングが表示された値を更新しないことに気付くことで、それを検出します。その場合、$ scope。$ digest()を呼び出してください。または、おそらく$ scope。$ apply()を使用できます
あなたはこのようにすることができます:
[〜#〜] html [〜#〜]
<div ng-hide="message"> <h2>show</h2> <div>
<div ng-hide="!message"> <h2>Hide</h2> </div>
[〜#〜] js [〜#〜]
$scope.message = true;
function merchantListController($scope, $http, $rootScope, $location, global) {
$http({
method: 'POST',
url: global.base_url + '/merchant/list',
}).success(function($data) {
if ($data.status === 'success') {
$scope.merchants = $data.data;
$scope.$apply(function(){
$scope.message = false;
$scope.$digest();
});
}
});
まず、$ scope。$ apply()の呼び出しは不要です。
show
divが表示されない場合、それは$scope.message = true;
は実行されません。実行されない場合は、AJAXリクエストが成功しないか、_$data.status === 'success'
は決して真実ではありません。
コードをデバッグするか、console.log()トレースを追加して変数の値を調べ、実行されているものとされていないものを確認します。標準デバッグ作業。
また、データ変数の先頭に$を付けないでください。通常、$は角度指定サービスに予約されています。