【问题标题】:breeze observableArray binding - are properties observable?微风 observableArray 绑定 - 属性是可观察的吗?
【发布时间】:2015-02-18 18:35:06
【问题描述】:

我有一个视图模型,它由 DoctorPrices 的列表(foreach 循环)组成,当单击列表中的一个项目时,它会在旁边打开一个 CRUD 表单。但是,当我更新 CRUD 上的值时,绑定到 foreach 的 observableArray 不会刷新? (尽管这些值在数据库中正确更新)

我从我的数据访问模块调用以下查询。

function getDoctorServices(doctorId) {
    var query = breeze.EntityQuery
         .from('DoctorPrices')
         .where('DoctorID', 'eq', doctorId).orderBy('ListOrder');
    return manager.executeQueryLocally(query);
}

在我的视图模型中,我有以下代码:

this.services = ko.computed(function() {
            return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
});

使用 foreach 循环绑定服务(不在这里发布,因为代码简单且有效

当我点击其中一个 DoctorPrices 时,它会按如下方式获取数据并将其放置在一个 observable 中:

this.selectedPrice = function (data, event) {
            self.currentService(data);
            self.showEdit(true);

        };

然后,我将 selectPrice 绑定到一个简单的表单,该表单具有可供用户修改的属性。然后我调用 manager.SaveChanges()。

这会导致以下问题:值正在正确更新,但在 foreach 中绑定的 GUI/原始列表未更新?微风中的属性不是可观察的吗?处理这样的事情的最佳方式是什么。

我想到了一种解决方法,并用这样的方式更改了代码:

doctorList.viewModel.instance.currentDoctorID.subscribe(function() {
            self.services([]);
            self.services(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
        });

但我觉得以这种方式清除数组是草率的,而不是专门处理长列表的正确方法。

有人可以为我指明正确的方向,了解如何正确绑定 observableArray 属性以便更新它们吗?

我的虚拟机组件的附加代码:

      function services() {
        var self = this;
        this.showForm = ko.observable(false);
        this.currentService = ko.observable();
        this.services = ko.observableArray(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
        this.title = ko.observable();


        doctorList.viewModel.instance.currentDoctorID.subscribe(function() {
            self.services([]);
            self.services(doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID()));
            self.showDetails(false);
        });


        this.show = function (value) {
            self.showForm(value);
        };


        this.showDetails = ko.observable(false);

        this.addNewService = function() {
            self.currentService(doctorServices.createService(doctorList.viewModel.instance.currentDoctorID()));
            console.log(self.currentService().entityAspect.entityState);
            self.showDetails(true);
        };

        this.showDelete = ko.computed(function() {
            if (self.currentService() == null)
                return false;
            else if (self.currentService().entityAspect.entityState.isDetached()) {
                self.title('Add new service');
                return false;
            } else {
                self.title('Edit service');
                return true;
            }
        });

        this.deleteService = function() {
            self.currentService().entityAspect.setDeleted();
            doctorServices.saveChanges();
            doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
        };

        this.closeDetails = function () {
            doctorServices.manager.rejectChanges();
            doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
            self.showDetails(false);
        };
        this.selectService = function (data, event) {
            self.currentService(data);
            self.showDetails(true);
        };
        this.saveChanges = function () {
            console.log(self.currentService().entityAspect.entityState);
            if (self.currentService().entityAspect.entityState.isDetached()) {
                doctorServices.attachEntity(self.currentService());
            }
            console.log(self.currentService().entityAspect.entityState);
            doctorServices.saveChanges();
            doctorList.viewModel.instance.currentDoctorID.notifySubscribers();
            self.currentService.notifySubscribers();
            self.showDetails(true);
        };


    }
    return {
        viewModel: {
            instance: new services()
        },
        template: servicesTemplate,
    };

下面是我的微风数据类:

 define('data/doctorServices', ['jquery', 'data/dataManager', 'knockout','mod/medappBase', 'breeze', 'breeze.savequeuing'], function ($, manager, ko,base, breeze, savequeuing) {
var services = ko.observableArray([]);


return {
    attachEntity:attachEntity,
    getServices: getServices,
    services: services,
    manager:manager,
    getDoctorServices: getDoctorServices,
    getServiceById: getServiceById,
    createService:createService,
    hasChanges: hasChanges,
    saveChanges: saveChanges
};



function getServices() {
    var query = breeze.EntityQuery.from("DoctorPrices");
    return manager.executeQuery(query).then(function (data) {
        services(data.results);
    }).fail(function (data) {
        console.log('fetch failed...');
        console.log(data);
    });;
}



function getDoctorServices(doctorId) {
    var query = breeze.EntityQuery
         .from('DoctorPrices')
         .where('DoctorID', 'eq', doctorId).orderBy('ListOrder');
    var set = manager.executeQueryLocally(query);

    return set;
}

function getServiceById(serviceId) {
    return manager.createEntity('DoctorPrice', serviceId);
    //return manager.getEntityByKey('DoctorPrice', serviceId);
}

function handleSaveValidationError(error) {
    var message = "Not saved due to validation error";
    try { // fish out the first error
        var firstErr = error.innerError.entityErrors[0];
        message += ": " + firstErr.errorMessage;
        base.addNotify('error', 'Could not save.', message);
    } catch (e) { /* eat it for now */ }
    return message;
}

function hasChanges() {
    return manager.hasChanges();
}

function attachEntity(entity) {
    manager.addEntity(entity);
}

function createService(doctorId) {
    return manager.createEntity('DoctorPrice', { DoctorPricingID: breeze.core.getUuid(), DoctorID:doctorId }, breeze.EntityState.Detached);

};


function saveChanges() {
    return manager.saveChanges()
        .then(saveSucceeded)
        .fail(saveFailed);

    function saveSucceeded(saveResult) {
        base.addNotify('success', 'Saved.', 'Your updates have been saved.');
    }

    function saveFailed(error) {
        var reason = error.message;
        var detail = error.detail;

        if (error.innerError.entityErrors) {
            reason = handleSaveValidationError(error);
        } else if (detail && detail.ExceptionType &&
            detail.ExceptionType.indexOf('OptimisticConcurrencyException') !== -1) {
            // Concurrency error 
            reason =
                "Another user, perhaps the server, " +
                "may have deleted one or all of the settings." +
                " You may have to restart the app.";
        } else {
            reason = "Failed to save changes: " + reason +
                     " You may have to restart the app.";
        }
        console.log(error);
        console.log(reason);
    }
}

});

请注意,这是我对数据类和虚拟机的第一次尝试。目前我严重依赖清除数组([])并使用 notifySubscribers 使数组刷新 :(

【问题讨论】:

    标签: breeze


    【解决方案1】:

    我敢打赌,您在某处遗漏了一个可观察对象。我不知道,因为您一直在从一个未显示定义的属性跳到另一个属性。

    比如我不知道你是怎么定义this.currentService的。

    我对此感到困惑:

    this.services = ko.computed(function() {
            return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
    });
    

    为什么是ko.computed?为什么不直接写an observable array

    self.service = ko.observableArray();
    
    // ... later replace the inner array in one step ...
    self.service(doctorServices.getDoctorServices(
        doctorList.viewModel.instance.currentDoctorID()));
    

    我敦促您遵循可观察性跟踪,确信您的 Breeze 实体属性确实是可观察的。

    【讨论】:

    • 感谢您的及时回复。它是计算出来的,因为 currentDoctorID 在下拉列表中更改,然后需要请求/过滤微风。我已经更新了顶部的可观察定义 - 这些是正确的,否则会引发错误。
    • 感谢所有的发布,我想我可能已经发现了我的错误,因为你正确地指出我将服务声明为可观察的而不是可观察的数组......所以我会看看那个和将定义从:this.services = ko.observable() 更改为 this.services = ko.observableArray()!!多么菜鸟的错误啊! (一定是深夜!)
    • 嗨,沃德。我再次尝试徒劳,即使我在操作基础数据时将可观察对象更改为数组,列表也不会更新 - 我认为我的问题是如果我运行一个简单的查询并将其绑定到一个列表,如果底层缓存更改(添加新记录等)列表会自动更新吗?还是需要重新查询和重新填充数组?
    • 列表应该会自动更新。我希望我知道在您的用例中误入歧途。你能提供一个超级简单的失败例子吗?它应该被剥去骨头。把它放在 gist 或 plunker 中。在我看来,您只需要一个带有一些虚假数据的 2 个实体模型(Doctor 和 DoctorPrice)来证明这一点。它不需要服务器。如需灵感,请查看没有服务器的this KO/Breeze example。这可能是您示例的起点。
    【解决方案2】:
     vm.selectedPrice  = ko.dependentObservable(function () {
    
           return doctorServices.getDoctorServices(doctorList.viewModel.instance.currentDoctorID());
    
    
        }, vm);
    

    vm 是你应用绑定的模型,试试这个它会起作用。

    【讨论】:

      猜你喜欢
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-12
      • 1970-01-01
      • 2020-11-20
      • 2017-07-12
      • 1970-01-01
      相关资源
      最近更新 更多