0

アプリケーションに2つのリストがあり、ユーザーは1つのリストから別のリストにアイテムをドラッグアンドドロップすることになっています。
ユーザーがリストの1つから別のリストに要素をドロップする場合、データベース(SelectedForDiscussion)のフィールドを更新するために、サーバー側のコードに対して要求を行う必要があります。
これは私のコントローラーのコードです:

$scope.$watch("questionsDiscuss", function (value) {
    var question = $.Enumerable.From($scope.questionsDiscuss).Where(function (item) { return !item.SelectedForDiscussion }).FirstOrDefault()
    if (question != undefined) {

        questionSelectionService.UpdateQuestionSelectionStatus(question.Id, true)
        .then(function (output) {

            var question = $.Enumerable.From($scope.questionsDiscuss)
                                .Where(function (item) { return item.Id == output.data.questionId })
                                .FirstOrDefault();
            var index = $.Enumerable.From($scope.questionsDiscuss).IndexOf(question);

            if (question != undefined)
                if (output.data.result != "success") {
                    $scope.questionsDiscuss.splice(index, 1);
                    $scope.questionsReceived.splice(0, 0, question);
                }
                else {
                    question.SelectedForDiscussion = true;
                    $scope.questionsDiscuss[index] = question;
                }
        });
    }
    else {
        var question = $.Enumerable.From($scope.questionsReceived).Where(function (item) { return item.SelectedForDiscussion }).FirstOrDefault();
        if (question != undefined) {
            questionSelectionService.UpdateQuestionSelectionStatus(question.Id, false)
            .then(function (output) {
                var question = $.Enumerable.From($scope.questionsReceived)
                                .Where(function (item) { return item.Id == output.data.questionId })
                                .FirstOrDefault();
                var index = $.Enumerable.From($scope.questionsReceived).IndexOf(question);

                if (question != undefined)
                    if (output.data.result != "success") {
                        $scope.questionsReceived.splice(index, 1);
                        $scope.questionsDiscuss.splice(0, 0, question);
                    }
                    else {
                        question.SelectedForDiscussion = false;
                        $scope.questionsReceived[index] = question;
                    }
            });
        }

    }

}, true);

Firebug内の次の行に4つのjavascriptブレークポイントを配置しています。
そのうちの2つは次の行にあります。

if (question != undefined) {

1つ:

var question = $.Enumerable.From($scope.questionsDiscuss)
    .Where(function (item) { 
        return item.Id == output.data.questionId 
     }) 
    .FirstOrDefault();

そして他の場所:

var question = $.Enumerable.From($scope.questionsReceived)
    .Where(function (item) { 
         return item.Id == output.data.questionId 
     })
    .FirstOrDefault();

次のことが起こります。

ブレークポイント:

if (question != undefined) {

常に到達します。

のブレークポイント

var question = $.Enumerable.From($scope.questionsDiscuss) 
    .Where(function (item) { 
         return item.Id == output.data.questionId 
    })
    .FirstOrDefault();

にも到達します。
もう一方には到達しません。
どちらの応答もOKです(応答コード200)。
すべてが完全に機能するはずですが、2番目のpromiseのthen句に到達することはありません。
誰かが私が間違っていることを教えてもらえますか?
サーバーサイドアプリケーションは、C#で記述されたASP.NETMVCアプリケーションです。

編集1:なぜこれが起こっているのかを理解し、回避策があります。私は実際の解決策に興味があります。
問題は、angularjsがエラーをスローし、$httpを2回呼び出すときにエラーを飲み込むことです。エラーは次のとおりです。

すでに進行中のダイジェスト

これは、私のディレクティブに次のコードがあるためだと思います。

dndfunc = function (scope, element, attrs) {

    // contains the args for this component
    var args = attrs.dndBetweenList.split(',');
    // contains the args for the target
    var targetArgs = $('#' + args[1]).attr('dnd-between-list').split(',');

    // variables used for dnd
    var toUpdate;
    var target;
    var startIndex = -1;

    // watch the model, so we always know what element
    // is at a specific position
    scope.$watch(args[0], function (value) {
        toUpdate = value;
    }, true);

    // also watch for changes in the target list
    scope.$watch(targetArgs[0], function (value) {
        target = value;
    }, true);

    // use jquery to make the element sortable (dnd). This is called
    // when the element is rendered
    $(element[0]).sortable({
        items: 'div',
        start: function (event, ui) {
            // on start we define where the item is dragged from
            startIndex = ($(ui.item).index());
        },
        stop: function (event, ui) {
            var newParent = ui.item[0].parentNode.id;

            // on stop we determine the new index of the
            // item and store it there
            var newIndex = ($(ui.item).index());
            var toMove = toUpdate[startIndex];

            // we need to remove him from the configured model
            toUpdate.splice(startIndex, 1);

            if (newParent == args[1]) {
                // and add it to the linked list
                target.splice(newIndex, 0, toMove);
            } else {
                toUpdate.splice(newIndex, 0, toMove);
            }

            // we move items in the array, if we want
            // to trigger an update in angular use $apply()
            // since we're outside angulars lifecycle
            scope.$apply(targetArgs[0]);
            scope.$apply(args[0]);
        },
        connectWith: '#' + args[1]
    })
}

そして、私が思うに、新しいダイジェストサイクルをトリガーする最後に適用する2つの呼び出しがあります。
とにかく、適用する呼び出しの前にこの呼び出しを追加することで修正しました。

            if (scope.updateLists != undefined)
                scope.updateLists();

そして、すべてのコードをウォッチからupdateLists関数に移動しました。

また、人々がサービスと関係があると言っているので、私はその中に関連するコードを貼り付けています:

GetQuestionsReceived: function (eid, criteria, page, rows) {

    var promise = this.GetQuestionsReceivedInternal(eid,criteria, page, rows).then(function (response) {
        // The return value gets picked up by the then in the controller.
        return response;
    });
    // Return the promise to the controller
    return promise;
},

GetQuestionsReceivedInternal: function (eid, criteria, page, rows) {

    return $http({ method: 'GET',
        url: '../QuestionManagement/GetQuestions?eventId='+eid+'&page=1&rows=5&'+serialize(criteria)
    }).
      success(function (data, status, headers, config) {
          // this callback will be called asynchronously
          // when the response is available
          results = data;
      }).
      error(function (data, status, headers, config) {
          // called asynchronously if an error occurs
          // or server returns response with an error status.
          if (window.console && console.log) {
              console.log("Could not obtain questions received. Error:" + data + "Status:" + status + "Headers:" + headers + "Config:" + config);
          }
      });
},

  GetQuestionsDiscuss: function (eid,criteria, page, rows) {

    var promise = this.GetQuestionsDiscussInternal(eid,criteria, page, rows).then(function (response) {
        // The return value gets picked up by the then in the controller.
        return response;
    });
    // Return the promise to the controller
    return promise;
},

GetQuestionsDiscussInternal: function (eid,criteria, page, rows) {

    return $http({ method: 'GET',
        url: '../QuestionManagement/GetQuestions?eventId=' + eid + '&page=1&rows=5&' + serialize(criteria)
    }).
      success(function (data, status, headers, config) {
          // this callback will be called asynchronously
          // when the response is available
          response = data;
      }).
      error(function (data, status, headers, config) {
          // called asynchronously if an error occurs
          // or server returns response with an error status.
          if (window.console && console.log) {
              console.log("Could not obtain questions received. Error:" + data + "Status:" + status + "Headers:" + headers + "Config:" + config);
          }
      });

},
4

1 に答える 1

0

2つの非常によく似たコードのブロックがあり、これらを一般化して関数ラッパーに配置すると、非常に単純な呼び出し関数が残ります。

すべてをその形式にまとめることができれば、デバッグが容易になると思います。

これがそうする試みです:

function updateSelectionStatus(qA, qB, bool) {
    var en = $.Enumerable.From(qA);
    var question = en.Where(function (item) {
        return bool ? !item.SelectedForDiscussion : item.SelectedForDiscussion;
    }).FirstOrDefault();
    if(question) {
        questionSelectionService.UpdateQuestionSelectionStatus(question.Id, bool).then(function (output) {
            if (output.data.result == "success") {
                question.SelectedForDiscussion = bool;
            }
            else {
                qA.splice(en.IndexOf(question), 1);
                qB.unshift(question);
            }
        });
    }
    return question;
}

$scope.$watch("questionsDiscuss", function (value) {
    if (!updateSelectionStatus($scope.questionsDiscuss, $scope.questionsReceived, true) {
        updateSelectionStatus($scope.questionsReceived, $scope.questionsDiscuss, false);
    }
}, true);

私はいくつかの誤った仮定をし、単純化しすぎた可能性があります(たとえば$.Enumerable.From、外側と同じ質問を再選択するように見える内側をパージする)ので、コードを作り直す必要があるかもしれません。

私はここで、解決策を提供するのではなく、原則を提唱しています。

于 2013-03-01T02:18:33.890 に答える