无法将来自 POST 的响应对象绑定到我的视图

Posted

技术标签:

【中文标题】无法将来自 POST 的响应对象绑定到我的视图【英文标题】:Cannot bind response object from POST to my view 【发布时间】:2016-05-22 04:57:12 【问题描述】:

我已经尝试解决这个问题好几个小时了,并试图在堆栈溢出和其他网站上找到一个可行的解决方案,但到目前为止都没有奏效。

问题

我正在构建一个 Travelogue Web 应用程序,允许用户记录和查看他们的旅程(例如公路旅行)。目前,我正在实现允许用户在从旅程列表中选择的单独视图中查看特定旅程的功能。我传递所选旅程的 id 并从 MongoDB 检索对象。我使用 POST 实现了这一点。它的工作原理是所选旅程的 _id 在请求中传递,然后用于使用 Model.findById 标识文档 - 然后响应产生数据。数据绑定到 $scope.selection。

但是,虽然 $scope.selection 包含数据(登录到控制台时),但我似乎无法将其绑定到视图(称为 view_journey)。意思是,每当我想访问时,例如在我的 view_journey.html 中的 selection.name,表达式或 ng-bind 为空。

app.js

$scope.viewJourneybyId = function(id) 
    var selectOne =  _id : id ;
    $http.post('http://localhost:8080/view_journey', selectOne).
    success(function(data) 
        $scope.selection = data;
        $scope.$apply();
        console.log("POST found the right Journey");
        console.log($scope.selection);
    ).error(function(data) 
        console.error("POST encountered an error");
    )    
  

server.js

app.post("/view_journey", function(request, response, next) 
   Journeys.findById(request.body._id, function(error, selection) 
      if (error)
         response.send(error)
      response.json( message: 'Journey found!', selection );
      );
   );

index.html

<tr ng-repeat="journey in journeys">
   <td>
      <a href="#/view_journey" ng-click="viewJourneybyId(journey._id)">
      journey.name</a>
   </td>
   <td>...</td>     
</tr>

view_journey.html

<div class="panel panel-default">
   <div class="panel-heading">
     <h2 ng-bind="selection.name"></h2>
     <!-- For Debugging -->
     ID <span ng-bind="selection._id">
   </div>
   <div class="panel-body">
     <table class=table>
        <caption>selection.desc</caption>
        ...
     </table>
   </div>
</div>

反馈 这是我关于堆栈溢出的第一个问题,所以请告诉我我是否以可能被误解的方式表达了我的问题,以及我是否应该提供更多细节,例如控制台输出。谢谢;)

【问题讨论】:

index.html 和 view_journey.html 有什么关系?看起来你有一个角度路由触发,如果是这样(通常)创建一个具有单独范围的新控制器实例,那么 $scope.selection 很可能确实是未定义的。尝试将 view_journey.html 与 index.html 放在同一个模板中,以测试您的数据流。或者,您必须提供有关应用程序结构的更多信息。 是的,我在 app.js 文件中设置了一个路由,但我只对整个应用程序使用了一个控制器 (mainCtrl)(是的,我知道,我应该尽快更改)...所以我认为这不是问题。此外,以完全相同的方式设置的其他路线确实可以访问相似的数据集。这是带有路由和 mainCtrl 的完整 app.js 文件:app.js 这是我的 server.js server.js 每当控制器附加到您的视图时,都会创建一个具有自己作用域的控制器的新实例。每当路由触发时都会发生这种情况,即使您使用具有不同模板的相同控制器也是如此。这意味着您的数据实际上并不存在于新控制器的范围内,除非您以某种方式将其放在那里。通常这是由工厂或服务部门完成的。我会仔细看看你的代码,看看我能看到什么。 谢谢,那太好了。 【参考方案1】:

在修改您的代码后,我可以确认在触发路由时,您将获得一个新的控制器实例,该实例具有一个新的、干净的范围。这是 AngularJS 的预期行为。

您可以通过添加一个简单的日志消息作为控制器的第一行来验证这一点:

console.log($scope.selected);

您会注意到它总是注销“未定义”,因为从未设置过变量(在 viewJourneyById 内)。如果您保留该登录并测试代码,您将在 viewJourneyById 中看到日志记录,但随后立即“未定义”,因为它将 view_journey.html 模板加载到 ng-view 并创建 mainCtrl 的新实例。新视图加载后“未定义”的存在表明控制器函数在路由更改时再次执行。

有几种方法可以解决这个问题。首先,您可以创建一个工厂或服务,将其注入您的控制器,并让它为您存储数据。这实际上是它们存在的原因之一,在控制器之间共享数据。

工厂:

travelogueApp.factory('myFactory',function() 
    return 
        selected: null,
        journeys: []
    ;
);

控制器:

travelogueApp.controller('mainCtrl', ['$scope','$http','$location','myFactory', function ($scope, $http, $location, myFactory) 
    // put it into the scope so the template can see it.
    $scope.factory = myFactory; 

    // do other stuff

    $scope.viewJourneybyId = function(id) 
        var selectOne =  _id : id ;
        $http.post('http://localhost:8080/view_journey', selectOne)
            .success(function(data) 
                $scope.factory.selection = data;
                console.log("POST found the right Journey");
                console.log($scope.factory.selection);
            )
            .error(function(data) 
                console.error("POST encountered an error");
            )    
          
    ]); // end controller

模板:

<div class="panel panel-default">
    <div class="panel-heading">
        <h2>factory.selection.name</h2>
    </div>
    <div class="panel-body">
        <table class=table>
        <caption>factory.selection.desc</caption>
        ...
        </table>
    </div>
</div>

或多或少是这样的。另一种方法是使用旅程 ID 构建链接作为查询字符串的一部分,然后在控制器中检查旅程 ID 的存在,如果找到,则查找旅程。这将是触发路由,加载控制器的新实例,然后在 view_journey 页面上加载数据的情况。您可以像这样在控制器中搜索查询字符串参数:

var journey_id = $location.search().id;

任何一种方式都有效。工厂/服务方法允许您通过存储一些数据来最大限度地减少 Web 服务调用。但是,您必须开始考虑数据管理,这样您的应用程序中就不会有过时的数据。查询字符串方式将是您解决问题的最快方式,但这意味着每个路由转换都将等待 Web 服务调用,即使您只是在相同的两个页面之间来回切换。

【讨论】:

以上是关于无法将来自 POST 的响应对象绑定到我的视图的主要内容,如果未能解决你的问题,请参考以下文章

无法在 django 视图中从 POST 检索数据

Xamarin Forms 1 视图绑定到多个对象

无法将子视图添加到我的 UIView

将图像从Firebase加载到我的表视图时出错

将基于缓存 Django 类的视图响应与请求中的参数绑定

来自 firebase 的数据未填充到我的表格视图中