thay đổi sự kiện khi lựa chọn với ràng buộc loại trực tiếp, làm thế nào tôi có thể biết liệu đó có phải là sự thay đổi thực sự hay không


87

Tôi đang xây dựng giao diện người dùng quyền, tôi có một danh sách các quyền với một danh sách chọn bên cạnh mỗi quyền. Các quyền được đại diện bởi một mảng đối tượng có thể quan sát được liên kết với một danh sách chọn:

<div data-bind="foreach: permissions">
     <div class="permission_row">
          <span data-bind="text: name"></span>
          <select data-bind="value: level, event:{ change: $parent.permissionChanged}">
                   <option value="0"></option>
                   <option value="1">R</option>
                   <option value="2">RW</option>
           </select>
      </div>
 </div>

Bây giờ vấn đề là thế này: sự kiện thay đổi được đưa ra khi giao diện người dùng mới xuất hiện lần đầu tiên. Tôi gọi hàm ajax của mình, lấy danh sách quyền và sau đó sự kiện được nêu ra cho từng mục quyền. Đây thực sự không phải là hành vi mà tôi muốn. Tôi muốn nó chỉ được nâng lên khi người dùng thực sự chọn ra một giá trị mới cho quyền trong danh sách lựa chọn , làm cách nào tôi có thể làm điều đó?

Câu trả lời:


107

Trên thực tế, bạn muốn tìm xem liệu sự kiện có được kích hoạt bởi người dùng hoặc chương trình hay không và sự kiện đó sẽ kích hoạt trong khi khởi chạy.

Cách tiếp cận loại trực tiếp của việc thêm subscriptionsẽ không giúp ích trong mọi trường hợp, tại sao vì trong hầu hết các mô hình sẽ được triển khai như thế này

  1. kết hợp mô hình với dữ liệu không xác định, chỉ cấu trúc (actual KO initilization)
  2. cập nhật mô hình với dữ liệu ban đầu (logical init like load JSON , get data etc)
  3. Tương tác người dùng và cập nhật

Bước thực tế mà chúng tôi muốn nắm bắt là các thay đổi trong 3, nhưng trong bước thứ hai subscriptionsẽ nhận được lệnh gọi, Vì vậy, cách tốt hơn là thêm vào thay đổi sự kiện như

 <select data-bind="value: level, event:{ change: $parent.permissionChanged}">

và phát hiện sự kiện trong permissionChangedchức năng

this.permissionChanged = function (obj, event) {

  if (event.originalEvent) { //user changed

  } else { // program changed

  }

}

5
Tôi nghĩ điều này nên được đánh dấu là câu trả lời đúng. Tôi đã có kịch bản chính xác như được mô tả trong câu hỏi và tôi đã thử nghiệm chuyển các chuỗi làm Chìa khóa cho selectphần tử. Tuy nhiên, ngay cả khi giá trị ban đầu của lựa chọn khớp với một trong các tùy chọn, nó vẫn kích hoạt changesự kiện. Khi tôi triển khai ifkhối đơn giản này trong trình xử lý, mọi thứ hoạt động như mong đợi. Hãy thử phương pháp này trước. Cảm ơn, @Sarath!
Pflugs

Tôi thích khái niệm phân biệt giữa người dùng đã thay đổi và chương trình được thay đổi. Điều này rất hữu ích trong các trường hợp hàng ngày, đặc biệt là với loại trực tiếp nơi các đối tượng quan sát có nhiều khả năng thay đổi giá trị mà không có bất kỳ tương tác nào của người dùng.
rodiwa

Đồng ý với @Pflugs, phân biệt giữa các loại sự kiện phù hợp với tôi và đây phải là câu trả lời được chấp nhận.
Emma Middlebrook

1
def phải là một câu trả lời ... sự kiện bất động sản loại được chấp nhận có thể được dùng để phân biệt kích hoạt của premissionChanged
caniaskyouaquestion

1
Cũng sử dụng phương pháp này để phát hiện xem người dùng có đang thay đổi lựa chọn thay vì một trình kích hoạt khác hay không. Trong trường hợp của tôi, việc cập nhật các giá trị tùy chọn thông qua liên kết "tùy chọn" đã kích hoạt sự kiện "thay đổi".
Nath

32

Đây chỉ là một phỏng đoán, nhưng tôi nghĩ nó xảy ra bởi vì levelnó là một con số. Trong trường hợp đó, valueràng buộc sẽ kích hoạt một changesự kiện để cập nhật levelvới giá trị chuỗi. Do đó, bạn có thể sửa lỗi này bằng cách đảm bảo levellà một chuỗi để bắt đầu.

Ngoài ra, cách thực hiện "Knockout" hơn là không sử dụng các trình xử lý sự kiện mà sử dụng các đối tượng có thể quan sát và đăng ký. Tạo levelmột mục có thể quan sát và sau đó thêm đăng ký vào đó, đăng ký này sẽ được chạy bất cứ khi nào levelthay đổi.


sau 2 giờ tìm hiểu nguyên nhân biểu mẫu của tôi kích hoạt sự kiện 'thay đổi' sau khi tải trang, bạn đoán đã cứu tôi.
Samih A

Câu trả lời của bạn đã cho tôi một ý tưởng ... Tôi đã cố tình thay đổi loại đến từ url, vì vậy chức năng đăng ký của tôi sẽ kích hoạt khi tải trang (tôi muốn nó xử lý var url, không chỉ khi trình đơn thả xuống của tôi kích hoạt thay đổi). Có cách nào ít hack hơn để làm điều này không?
Jiffy

4

Đây là một giải pháp có thể giúp giải quyết hành vi kỳ lạ này. Tôi không thể tìm thấy giải pháp tốt hơn là đặt một nút để kích hoạt sự kiện thay đổi theo cách thủ công.

CHỈNH SỬA: Có thể một ràng buộc tùy chỉnh như thế này có thể giúp:

ko.bindingHandlers.changeSelectValue = {

   init: function(element,valueAccessor){

        $(element).change(function(){

            var value = $(element).val();

            if($(element).is(":focus")){

                  //Do whatever you want with the new value
            }

        });

    }
  };

Và trong thuộc tính data-bind đã chọn của bạn, hãy thêm:

changeSelectValue: yourSelectValue

oh ... bạn có ý nghĩa như một nút tiết kiệm .. không tốt cho tôi .. tôi thực sự chỉ cần điều này để làm việc :)?
anh chàng schaller

Chỉnh sửa câu trả lời với một giải pháp tốt hơn (hy vọng).
Ingro

Này Ingro, điều này đã được gắn cờ (không chính xác) vì không phải là câu trả lời. Tôi đã sửa lại câu đầu tiên của bạn để người gắn cờ sẽ không vô tình nghĩ rằng bạn đang đăng câu hỏi làm câu trả lời. Hi vọng điêu nay co ich! :)
jmort253

@ jmort253: xin lỗi, đó là lỗi của tôi. Tốt hơn là không nên trả lời bằng cách sử dụng "Tôi cũng có vấn đề tương tự", vì điều này có vẻ như bạn đang hỏi điều gì khác. Thay vào đó, hãy trực tiếp đưa ra giải pháp cho một câu trả lời và giải thích cách hoạt động của nó.
Qantas 94 Heavy

1
Vâng xin lỗi, sai lầm của tôi. Đó là một trong những câu trả lời đầu tiên tôi đăng trên stackoverflow và không biết tất cả các quy tắc. Cảm ơn vì đã chỉnh sửa!
Ingro

3

Tôi sử dụng tùy chỉnh này ràng buộc (dựa trên này fiddle bởi RP Niemeyer, xem câu trả lời của mình để này câu hỏi), mà làm cho chắc chắn rằng các giá trị số được chuyển đổi hoàn toàn khỏi chuỗi số (theo đề nghị của các giải pháp của Michael xuất sắc nhất):

Javascript:

ko.bindingHandlers.valueAsNumber = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var observable = valueAccessor(),
            interceptor = ko.computed({
                read: function () {
                    var val = ko.utils.unwrapObservable(observable);
                    return (observable() ? observable().toString() : observable());
                },
                write: function (newValue) {
                    observable(newValue ? parseInt(newValue, 10) : newValue);
                },
                owner: this
            });
        ko.applyBindingsToNode(element, { value: interceptor });
    }
};

HTML mẫu:

<select data-bind="valueAsNumber: level, event:{ change: $parent.permissionChanged }">
    <option value="0"></option>
    <option value="1">R</option>
    <option value="2">RW</option>
</select>

2

Nếu bạn sử dụng một giá trị có thể quan sát được thay vì một giá trị nguyên thủy, thì vùng chọn sẽ không tăng các sự kiện thay đổi trên ràng buộc ban đầu. Bạn có thể tiếp tục liên kết với sự kiện thay đổi, thay vì đăng ký trực tiếp vào sự kiện có thể quan sát được.


1

Nhanh chóng và bẩn thỉu, sử dụng một lá cờ đơn giản:

var bindingsApplied = false;

var ViewModel = function() {
    // ...

    this.permissionChanged = function() {
        // ignore, if flag not set
        if (!flag) return;

        // ...
    };
};

ko.applyBindings(new ViewModel());
bindingsApplied = true; // done with the initial population, set flag to true

Nếu cách này không hiệu quả, hãy thử gói dòng cuối cùng trong setTimeout () - các sự kiện không đồng bộ, vì vậy có thể sự kiện cuối cùng vẫn đang chờ xử lý khi applyBindings () đã được trả về.


xin chào, cảm ơn bạn đã trả lời, điều này sẽ không hoạt động với tôi vì tôi gọi ko.applyBindings khi dom đã sẵn sàng, nhưng các quyền của tôi a đang được điền vào mô hình của tôi ở giai đoạn sau ... vì vậy cờ sẽ đúng nhưng vấn đề vẫn sẽ xảy ra.
anh chàng schaller

0

Tôi đã gặp sự cố tương tự và tôi vừa sửa đổi trình xử lý sự kiện để kiểm tra loại biến. Loại chỉ được đặt sau khi người dùng chọn một giá trị, không phải khi trang được tải lần đầu tiên.

self.permissionChanged = function (l) {
    if (typeof l != 'undefined') {
        ...
    }
}

Điều này dường như làm việc cho tôi.


0

dùng cái này:

this.permissionChanged = function (obj, event) {

    if (event.type != "load") {

    } 
}

0

Hãy thử cái này:

self.GetHierarchyNodeList = function (data, index, event)
{
    debugger;
    if (event.type != "change") {
        return;
    }        
} 

event.type == "change"
event.type == "load" 

Tham số thứ 2 không phải là chỉ mục, đối với tôi đó là sự kiện.
sairfan

@sairfan thêm vài tham số cho hàm và tìm từ đó tham số bạn nhận được sự kiện sử dụng debugger
Chanaka Sampath

-1

Nếu bạn đang làm việc bằng Knockout, hãy sử dụng chức năng chính của loại bỏ chức năng quan sát được.
Sử dụng ko.computed()phương thức và thực hiện và kích hoạt lệnh gọi ajax trong hàm đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.