angular 除非使用超时,否则通过 $http 传输的对象与之前的输出不同
angular object transferred via $http differs from beforehand output unless timeout is used
我创建了一个带有 2 向对象数据绑定的嵌套指令结构。
在 js 方面,一切都像一个魅力,直到我将它连接到我的服务,将数据发送到我的 api。
因为在 post 请求中对象有旧值,它总是忽略最新的变化。但真正的问题是......在我将对象传递给请求之前输出对象,它具有正确的更新值。
service.updatePerson = function(person) {
console.log(person); //this outputs the correct up to date data
$http.post(Routing.generate('update_person'), person); // this works not
//After trying some more (see update below) - this works as well
$timeout(function() {
$http.post(Routing.generate('update_person'), person);
}, 1000);
};
(我正在使用 symfony 的 fos 路由包)
使用我的开发人员工具检查请求,我可以看到提交的对象具有旧值。但它不像值永远不会改变,它总是最后一次但不是当前的变化。
我是 angular 的新手,可能会忽略 $http 服务的一些特殊之处 - 我没有启用缓存,所以这应该不是问题所在。
此外,问题仅发生在更新的对象上,如果我发送一个完整的新实体则不会。
我能看到并且我怀疑会导致问题的唯一区别是嵌套的深度。
我有一个名为 'collapsedTable' 的指令,它接受不同的数据。不仅是数据,更新、添加和删除方法也被传递给指令。
这是指令的用法:
<collapsed-table ng-if="formModel" ng-if="persons" view-data="persons" form-model="formModel" add-object="newPerson" add-item="addPerson(item)" update-item="updatePerson(item)" delete-item="deletePerson(item)"></collapsed-table>
直接在指令中添加和删除项目:
<button href="#" class="btn btn-success pull-right" ng-click="addItem({item : newItem})">
Add
</button>
(删除按钮看起来一样,但是调用了删除功能)
但是更新数据不是通过一个按钮发生的,它直接绑定到表单字段并且表单字段是它自己的指令:
<form-field ng-if="column.type" form-field-bind="item[column.name]" form-field-action="updateItem({item:item})" form-field-action-param="item" form-select-options="column.data" form-template="{{column.type}}"></form-field>
(我知道,这里发生的一般狗屎)
并在指令中(例如 editableTextarea):
<a href="#" onaftersave="formFieldAction({item : formFieldActionParam})" editable-textarea="$parent.formFieldBind">{{formFieldBind || 'eintragen'}}</a>
(此处使用 angular 的 x-editable 模块)
我认为 post 阅读我的指令的全部内容太过分了。但我认为范围设置与理解函数和变量的传递方式有关。
collapsedTableDirective.js
.directive('collapsedTable',['$filter',function($filter) {
return {
restrict: 'E',
templateUrl: 'templates/collapsedTableView.html',
scope: {
data: "=viewData",
newItem: '=addObject',
formModel: '=',
deleteItem: '&',
updateItem: '&',
addItem: '&'
}
}
}]);
formFieldDirective.js
.directive('formField',['formTemplateFactory', '$filter',function(formTemplateFactory, $filter) {
return {
restrict: 'E',
scope: {
formFieldBind: '=',
formFieldActionParam: '=',
formFieldAction: '&',
formTemplate: '@',
formSelectOptions: '='
},
transclude: true,
template: '<div ng-include="getTemplate()"></div>'
}
}]);
我还展示了表单字段模板是通过 ng-include 提取的,它创建了一个新的范围,这就是为什么在表单字段模板中使用 "parent" 引用绑定变量的原因。
但是对于所有可能在这里讨论的问题,请不要忘记:
console.log
在服务中输出正确的数据。只有在请求中我们有旧数据。这也是 ist 有点难以调试的原因......从调试器方面来看,我的对象总是看起来很好。
感谢任何帮助!
更新 - $timeout 有效
尝试了一些东西之后,我有了尝试 timeout
的想法(来自完全不相关的 post)。是的,超时可以解决问题。
但我没有回答这个问题,因为我真的没有对这种行为的解释。 console.log
不需要超时,尽管它应该在 post 请求之前执行。
此外,可能还有比使用超时更合适的解决方案。
person
在 service.updatePerson
运行时没有更新,看起来它是由不适应摘要周期的非 Angular 代码触发的。在这种情况下,这个
$scope.$apply();
// or $rootScope.$apply() if this is a service and not a controller
$http.post(Routing.generate('update_person'), person);
可能会有所帮助,尽管在调用者函数中执行 $apply
而不是被调用者始终是一个更好的习惯,因此外部 JS 应该触发包装器:
scope.externalAction = function (obj) {
scope.$apply(function () {
scope.formFieldAction(obj);
};
};
console.log
不输出当时实际的数据,因为它是由对象引用提供的,它可能反映了调用 console.log
之后发生的变化。如果考虑到这一点,这是一个有用的功能,否则就是有害的。
要记录当前对象状态总是使用
console.log(JSON.stringify(person));
我创建了一个带有 2 向对象数据绑定的嵌套指令结构。 在 js 方面,一切都像一个魅力,直到我将它连接到我的服务,将数据发送到我的 api。 因为在 post 请求中对象有旧值,它总是忽略最新的变化。但真正的问题是......在我将对象传递给请求之前输出对象,它具有正确的更新值。
service.updatePerson = function(person) {
console.log(person); //this outputs the correct up to date data
$http.post(Routing.generate('update_person'), person); // this works not
//After trying some more (see update below) - this works as well
$timeout(function() {
$http.post(Routing.generate('update_person'), person);
}, 1000);
};
(我正在使用 symfony 的 fos 路由包)
使用我的开发人员工具检查请求,我可以看到提交的对象具有旧值。但它不像值永远不会改变,它总是最后一次但不是当前的变化。
我是 angular 的新手,可能会忽略 $http 服务的一些特殊之处 - 我没有启用缓存,所以这应该不是问题所在。 此外,问题仅发生在更新的对象上,如果我发送一个完整的新实体则不会。
我能看到并且我怀疑会导致问题的唯一区别是嵌套的深度。 我有一个名为 'collapsedTable' 的指令,它接受不同的数据。不仅是数据,更新、添加和删除方法也被传递给指令。
这是指令的用法:
<collapsed-table ng-if="formModel" ng-if="persons" view-data="persons" form-model="formModel" add-object="newPerson" add-item="addPerson(item)" update-item="updatePerson(item)" delete-item="deletePerson(item)"></collapsed-table>
直接在指令中添加和删除项目:
<button href="#" class="btn btn-success pull-right" ng-click="addItem({item : newItem})">
Add
</button>
(删除按钮看起来一样,但是调用了删除功能)
但是更新数据不是通过一个按钮发生的,它直接绑定到表单字段并且表单字段是它自己的指令:
<form-field ng-if="column.type" form-field-bind="item[column.name]" form-field-action="updateItem({item:item})" form-field-action-param="item" form-select-options="column.data" form-template="{{column.type}}"></form-field>
(我知道,这里发生的一般狗屎)
并在指令中(例如 editableTextarea):
<a href="#" onaftersave="formFieldAction({item : formFieldActionParam})" editable-textarea="$parent.formFieldBind">{{formFieldBind || 'eintragen'}}</a>
(此处使用 angular 的 x-editable 模块)
我认为 post 阅读我的指令的全部内容太过分了。但我认为范围设置与理解函数和变量的传递方式有关。
collapsedTableDirective.js
.directive('collapsedTable',['$filter',function($filter) {
return {
restrict: 'E',
templateUrl: 'templates/collapsedTableView.html',
scope: {
data: "=viewData",
newItem: '=addObject',
formModel: '=',
deleteItem: '&',
updateItem: '&',
addItem: '&'
}
}
}]);
formFieldDirective.js
.directive('formField',['formTemplateFactory', '$filter',function(formTemplateFactory, $filter) {
return {
restrict: 'E',
scope: {
formFieldBind: '=',
formFieldActionParam: '=',
formFieldAction: '&',
formTemplate: '@',
formSelectOptions: '='
},
transclude: true,
template: '<div ng-include="getTemplate()"></div>'
}
}]);
我还展示了表单字段模板是通过 ng-include 提取的,它创建了一个新的范围,这就是为什么在表单字段模板中使用 "parent" 引用绑定变量的原因。
但是对于所有可能在这里讨论的问题,请不要忘记:
console.log
在服务中输出正确的数据。只有在请求中我们有旧数据。这也是 ist 有点难以调试的原因......从调试器方面来看,我的对象总是看起来很好。
感谢任何帮助!
更新 - $timeout 有效
尝试了一些东西之后,我有了尝试 timeout
的想法(来自完全不相关的 post)。是的,超时可以解决问题。
但我没有回答这个问题,因为我真的没有对这种行为的解释。 console.log
不需要超时,尽管它应该在 post 请求之前执行。
此外,可能还有比使用超时更合适的解决方案。
person
在 service.updatePerson
运行时没有更新,看起来它是由不适应摘要周期的非 Angular 代码触发的。在这种情况下,这个
$scope.$apply();
// or $rootScope.$apply() if this is a service and not a controller
$http.post(Routing.generate('update_person'), person);
可能会有所帮助,尽管在调用者函数中执行 $apply
而不是被调用者始终是一个更好的习惯,因此外部 JS 应该触发包装器:
scope.externalAction = function (obj) {
scope.$apply(function () {
scope.formFieldAction(obj);
};
};
console.log
不输出当时实际的数据,因为它是由对象引用提供的,它可能反映了调用 console.log
之后发生的变化。如果考虑到这一点,这是一个有用的功能,否则就是有害的。
要记录当前对象状态总是使用
console.log(JSON.stringify(person));