Angularjs 模型中的角度选择绑定断开引用

Angularjs 模型中的角度选择绑定断开引用,angularjs,typescript,Angularjs,Typescript,角度版本是1.4.7 所讨论的模型包含两个对象:“系统”、一个数组和“selectedSystem”。我希望selectedSystem引用系统中的一个对象。页面加载时就是这种情况,一切正常,但当我从第一个下拉列表中进行选择时,selectedSystem似乎成为系统中原始对象的副本,而不是引用。因此,对第二个下拉列表的更改不再反映在系统中 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <he

角度版本是1.4.7

所讨论的模型包含两个对象:“系统”、一个数组和“selectedSystem”。我希望selectedSystem引用系统中的一个对象。页面加载时就是这种情况,一切正常,但当我从第一个下拉列表中进行选择时,selectedSystem似乎成为系统中原始对象的副本,而不是引用。因此,对第二个下拉列表的更改不再反映在系统中

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello</title>
</head>
<body ng-app="testApp">
    Hi There!
    <div ng-controller="TestAppSummaryCtrl">
        <input type="button" value="Add Query" ng-click="addQuery()"/>
        <select ng-model="state.selectedSystem" ng-options="system.description for system in state.systems track by system.systemId" ></select>
        <select ng-model="state.selectedSystem.currentEnvironment" ng-options="environment.description for environment in state.selectedSystem.environments track by environment.environmentId"></select>
        Selected System: {{state.selectedSystem.systemId}}

        <div ng-repeat="item in state.systems">
            System: {{item.description}}
            Current Environment: {{item.currentEnvironment.description}}
        </div>

        <div ng-repeat="item in state.selectedSystem.categories">
            Cateogry:
            {{item.categoryId}}
            {{item.description}}
            <br />
            Queries:
            <div ng-repeat="query in item.queries">
                {{query.queryId}}
                {{query.latestStatus}}
            </div>
        </div>
    </div>
    <script src="../Scripts/angular.js"></script>
    <script src="../Scripts/angular-route.js"></script>
    <script src="src/test.js"></script>
</body>
</html>

你好
你好!
所选系统:{{state.selectedSystem.systemId}
系统:{{item.description}
当前环境:{{item.currentEnvironment.description}
分类:
{{item.categoryId}
{{item.description}

查询: {{query.queryId} {{query.latestStatus}
打字脚本代码:

/// <reference path="../../scripts/typings/angularjs/angular.d.ts" />
/// <reference path="../../scripts/typings/angularjs/angular-route.d.ts" />

module TestApp {
    export class Config {
        constructor($routeProvider: ng.route.IRouteProvider) {
            $routeProvider.when("/test", {
                templateUrl: "StaticContent/StaticTest.html",
                controller: "TestAppCtrl"
            });
        }
    }

    Config.$inject = ['$routeProvider'];

    export class SummaryService {
        private summaryApiPath: string;
        private httpService: ng.IHttpService;
        private qService: ng.IQService;
        private systems: Array<Extensions.SystemSummary>;

        constructor($http: ng.IHttpService, $q: ng.IQService) {
            this.summaryApiPath = "../api/systemList";
            this.httpService = $http;
            this.qService = $q;
        }

        getSystems(): ng.IPromise<any> {
            if (this.systems != undefined) {
                return this.qService.when(this.systems);
            }
            var deferred = this.qService.defer();
            this.httpService.get(this.summaryApiPath).then((result: any) => {
                deferred.resolve(result.data);
            }), error => {
                deferred.reject(error);
            }
            return deferred.promise;
        }

        public static serviceFactory($http: ng.IHttpService, $q: ng.IQService): SummaryService {
            return new SummaryService($http, $q);
        }
    }

    export class TestAppSummaryCtrl {
        private $scope: Extensions.ISummaryScope
        private summaryService: SummaryService;

        private init(): void {
            var local = this.$scope;
            this.summaryService.getSystems().then(data => {
                local.state.systems = <Array<Extensions.SystemSummary>>data;
                local.state.selectedSystem = local.state.systems.length == 0 ? undefined : local.state.systems[0];
            });
            local.updateCurrentEnvironment = envId => local.state.selectedSystem.currentEnvironment = local.state.selectedSystem.environments[envId];
        }

        constructor($scope: Extensions.ISummaryScope, summaryService: SummaryService) {
            this.$scope = $scope;
            this.$scope.state = new Extensions.SummaryCtrlUIState();
            this.summaryService = summaryService;
            this.init();
        }
    }

    TestAppSummaryCtrl.$inject = ['$scope', 'summaryService'];

    var app = angular.module('testApp', ['ngRoute']);
    app.config(Config);
    app.factory('summaryService', ['$http', '$q', SummaryService.serviceFactory]);
    app.controller('TestAppSummaryCtrl', TestAppSummaryCtrl);
}

module Extensions {
    export class CategorySummary {
        categoryId: number;
        description: number;
        queries: Array<JobItemSummary>;
    }

    export class JobItemSummary {
        queryId: number;
        lastJobId: number;
        lastCompletedDate: string;
        latestStatus: string;
        latestResultsCount: number;
        latestResultsSummary: string;
        expectedResult: number;
    }

    export class EnvironmentSummary {
        environmentId: number;
        description: string;
    }

    export class SystemSummary {
        systemId: number;
        description: string;
        environments: Array<EnvironmentSummary>;
        currentEnvironment: EnvironmentSummary;
        categories: Array<CategorySummary>;
    }

    export class SummaryCtrlUIState {
        selectedSystem: Extensions.SystemSummary;
        systems: Array<Extensions.SystemSummary>;
    }

    export interface ISummaryScope extends ng.IScope {

        state: SummaryCtrlUIState;
        updateCurrentEnvironment(envId: number): void;
        addQuery(): void; 
    }
}
//
/// 
模块TestApp{
导出类配置{
构造函数($routeProvider:ng.route.iroutProvider){
$routeProvider.when(“/test”{
templateUrl:“StaticContent/StaticTest.html”,
控制器:“TestAppCtrl”
});
}
}
配置$inject=['$routeProvider'];
导出类摘要服务{
私有summaryapath:string;
私有httpService:ng.IHttpService;
私人qService:ng.IQService;
专用系统:阵列;
构造函数($http:ng.IHttpService,$q:ng.IQService){
this.summaryApiPath=“../api/systemList”;
this.httpService=$http;
this.qService=$q;
}
getSystems():ng.IPromise{
如果(this.systems!=未定义){
返回此.qService.when(此.systems);
}
var deferred=this.qService.deferred();
this.httpService.get(this.summaryApiPath).then((结果:any)=>{
延迟。解析(结果。数据);
}),错误=>{
延迟。拒绝(错误);
}
回报。承诺;
}
公共静态服务工厂($http:ng.IHttpService,$q:ng.IQService):SummaryService{
返回新的SummaryService($http,$q);
}
}
导出类TestAppSummaryCtrl{
私有$scope:Extensions.ISummaryScope
专用汇总服务:汇总服务;
private init():void{
var local=此。$scope;
this.summaryService.getSystems().then(数据=>{
local.state.systems=数据;
local.state.selectedSystem=local.state.systems.length==0?未定义:local.state.systems[0];
});
local.updateCurrentEnvironment=envId=>local.state.selectedSystem.currentEnvironment=local.state.selectedSystem.environments[envId];
}
构造函数($scope:Extensions.ISummaryScope,summaryService:summaryService){
这个.$scope=$scope;
this.$scope.state=new Extensions.summaryCtrluyState();
this.summaryService=summaryService;
this.init();
}
}
TestAppSummaryCtrl.$inject=['$scope','summaryService'];
var app=angular.module('testApp',['ngRoute']);
app.config(config);
app.factory('summaryService',['http','q',summaryService.serviceFactory]);
应用程序控制器(“TestAppSummaryCtrl”,TestAppSummaryCtrl);
}
模块扩展{
导出类分类摘要{
类别ID:编号;
说明:编号;
查询:数组;
}
导出类JobItemSummary{
queryId:编号;
lastJobId:编号;
lastCompletedDate:字符串;
最新状态:字符串;
最新结果:编号;
最新结果摘要:字符串;
预期结果:数量;
}
导出类环境摘要{
environmentId:编号;
描述:字符串;
}
导出类系统摘要{
systemId:编号;
描述:字符串;
环境:阵列;
当前环境:环境概述;
类别:阵列;
}
导出类SummaryCtrlUIState{
selectedSystem:Extensions.SystemSummary;
系统:阵列;
}
导出接口ISummaryScope扩展了ng.IScope{
状态:SummaryCtrlUIState;
updateCurrentEnvironment(envId:number):无效;
addQuery():void;
}
}

发生了什么,有什么方法可以通过角度模型绑定获得我想要的行为吗?

来自未来的问候

有一个和你相似的问题,既然这已经一年多了,我想我应该做一些挖掘。这似乎是经过设计的,即使在v1.6中也是如此

是的,
track by
正在将值复制到您的
ngModel
。目前,我认为唯一的办法是编写自己的逻辑来跟踪选择和/或将更改发送回原始阵列


编辑:我在angular.js github repo上打开了一个问题:

我刚刚发现,从ng选项中删除“track by”部分,一切正常。我仍然不确定track by为什么会导致这种行为。有人能解释一下吗?
        getViewValueFromOption: function(option) {
            // If the viewValue could be an object that may be mutated by the application,
            // we need to make a copy and not return the reference to the value on the option.
            return trackBy ? copy(option.viewValue) : option.viewValue;
        }