[javascript] Knockout.js에서 관찰 가능한 바인딩을 지우거나 제거하는 방법은 무엇입니까?

사용자가 여러 번 수행 할 수있는 기능을 웹 페이지에 구축하고 있습니다. 사용자의 액션을 통해 ko.applyBindings ()를 사용하여 객체 / 모델을 생성하고 HTML에 적용합니다.

데이터 바인딩 된 HTML은 jQuery 템플릿을 통해 생성됩니다.

여태까지는 그런대로 잘됐다.

두 번째 개체 / 모델을 만들고 ko.applyBindings ()를 호출하여이 단계를 반복하면 두 가지 문제가 발생합니다.

  1. 마크 업은 이전 개체 / 모델과 새 개체 / 모델을 표시합니다.
  2. 객체 / 모델의 속성 중 하나와 관련하여 자바 스크립트 오류가 발생하지만 여전히 마크 업에 렌더링되어 있습니다.

이 문제를 해결하기 위해 첫 번째 패스 후 jQuery의 .empty ()를 호출하여 모든 데이터 바인딩 속성을 포함하는 템플릿 HTML을 제거하여 더 이상 DOM에 있지 않도록합니다. 사용자가 두 번째 패스를 위해 프로세스를 시작하면 데이터 바인딩 된 HTML이 DOM에 다시 추가됩니다.

그러나 내가 말했듯이 HTML이 DOM에 다시 추가되고 새 개체 / 모델에 다시 바인딩되면 첫 번째 개체 / 모델의 데이터가 여전히 포함되며 발생하지 않는 JS 오류가 계속 발생합니다. 첫 번째 패스 동안.

결론은 마크 업이 DOM에서 제거되었지만 Knockout이 이러한 바인딩 된 속성을 유지하고 있다는 것입니다.

그래서 제가 찾고있는 것은 Knockout에서 이러한 바인딩 된 속성을 제거하는 수단입니다. 더 이상 관찰 가능한 모델이 없다고 녹아웃에게 말하고 있습니다. 이를 수행하는 방법이 있습니까?

편집하다

기본 프로세스는 사용자가 파일을 업로드하는 것입니다. 그런 다음 서버는 JSON 개체로 응답하고 데이터 바인딩 된 HTML이 DOM에 추가 된 다음 JSON 개체 모델이 다음을 사용하여이 HTML에 바인딩됩니다.

mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);

사용자가 모델에서 일부를 선택하면 동일한 객체가 서버에 다시 게시되고 데이터 바인딩 된 HTML이 DOM에서 제거되고 다음 JS가 생성됩니다.

mn.AccountCreationModel = null;

사용자가이 작업을 한 번 더 원하면이 모든 단계가 반복됩니다.

jsFiddle 데모를 수행하기에는 코드가 너무 ‘관련’되어 있습니다.



답변

DOM 요소에서 녹아웃의 깨끗한 노드 메서드를 호출하여 메모리 바인딩 된 개체를 처리해 보셨습니까?

var element = $('#elementId')[0];
ko.cleanNode(element);

그런 다음 새 뷰 모델로 해당 요소에만 녹아웃 바인딩을 다시 적용하면 뷰 바인딩이 업데이트됩니다.


답변

작업중인 프로젝트의 ko.unapplyBindings경우 jQuery 노드와 부울 제거를 허용하는 간단한 함수를 작성했습니다 . ko.cleanNode메서드가 처리하지 않으므로 먼저 모든 jQuery 이벤트의 바인딩을 해제합니다 . 메모리 누수를 테스트했는데 제대로 작동하는 것 같습니다.

ko.unapplyBindings = function ($node, remove) {
    // unbind events
    $node.find("*").each(function () {
        $(this).unbind();
    });

    // Remove KO subscriptions and references
    if (remove) {
        ko.removeNode($node[0]);
    } else {
        ko.cleanNode($node[0]);
    }
};


답변

녹아웃이 제공하는 with binding을 사용해 볼 수 있습니다.
http://knockoutjs.com/documentation/with-binding.html
적용 바인딩을 한 번 사용하고 데이터가 변경 될 때마다 모델을 업데이트하는 것이 아이디어입니다.

최상위 뷰 모델 storeViewModel, cartViewModel로 표시되는 카트 및 해당 카트의 항목 목록 (예 : cartItemsViewModel)이 있다고 가정 해 보겠습니다.

최상위 모델 인 storeViewModel을 전체 페이지에 바인딩합니다. 그런 다음 카트 또는 카트 항목을 담당하는 페이지 부분을 분리 할 수 ​​있습니다.

cartItemsViewModel에 다음 구조가 있다고 가정합니다.

var actualCartItemsModel = { CartItems: [
  { ItemName: "FirstItem", Price: 12 },
  { ItemName: "SecondItem", Price: 10 }
] }

cartItemsViewModel은 처음에 비어있을 수 있습니다.

단계는 다음과 같습니다.

  1. html로 바인딩을 정의하십시오. cartItemsViewModel 바인딩을 분리합니다.

      
        <div data-bind="with: cartItemsViewModel">
          <div data-bind="foreach: CartItems">
            <span data-bind="text: ItemName"></span>
            <span data-bind="text: Price"></span>
          </div>
        </div>
      
    
  2. 상점 모델은 서버에서 가져옵니다 (또는 다른 방법으로 생성됨).

    var storeViewModel = ko.mapping.fromJS(modelFromServer)

  3. 최상위 뷰 모델에서 빈 모델을 정의합니다. 그런 다음 해당 모델의 구조를 실제 데이터로 업데이트 할 수 있습니다.

      
        storeViewModel.cartItemsViewModel = ko.observable();
        storeViewModel.cartViewModel = ko.observable();
     
    
  4. 최상위 뷰 모델을 바인딩합니다.

    ko.applyBindings(storeViewModel);

  5. cartItemsViewModel 개체를 사용할 수 있으면 이전에 정의한 자리 표시 자에 할당합니다.

    storeViewModel.cartItemsViewModel(actualCartItemsModel);

장바구니 항목을 지우려면 :
storeViewModel.cartItemsViewModel(null);

Knockout은 html을 처리합니다. 즉, 모델이 비어 있지 않을 때 나타나고 div의 내용 ( “바인딩 포함”이있는 내용)이 사라집니다.


답변

검색 버튼을 클릭 할 때마다 ko.applyBinding을 호출해야하며 필터링 된 데이터는 서버에서 반환되며이 경우에는 ko.cleanNode를 사용하지 않고 다음 작업을 수행합니다.

foreach를 템플릿으로 바꾸면 collections / observableArray의 경우 잘 작동 할 것임을 경험했습니다.

이 시나리오가 유용 할 수 있습니다.

<ul data-bind="template: { name: 'template', foreach: Events }"></ul>

<script id="template" type="text/html">
    <li><span data-bind="text: Name"></span></li>
</script>


답변

KO의 내부 함수를 사용하고 JQuery의 포괄적 인 이벤트 핸들러 제거를 처리하는 대신에 with또는 template바인딩을 사용하는 것이 훨씬 더 좋습니다 . 이렇게하면 ko는 DOM의 해당 부분을 다시 생성하므로 자동으로 정리됩니다. 이것은 또한 권장되는 방법입니다. https://stackoverflow.com/a/15069509/207661을 참조하십시오 .


답변

바인딩을 전체 시간 동안 유지하고 관련 데이터를 업데이트하는 것이 더 나을 것이라고 생각합니다. 이 문제가 발생하여 .resetAll()데이터를 보관하고있는 배열에서 메서드를 사용하여 호출하는 것이 가장 효과적인 방법이라는 것을 알았습니다.

기본적으로 ViewModel을 통해 렌더링 할 데이터를 포함하는 전역 변수로 시작할 수 있습니다.

var myLiveData = ko.observableArray();

myLiveData정상적인 배열을 만들 수 없다는 것을 깨닫는 데 시간이 걸렸습니다 ko.oberservableArray. 부품이 중요했습니다.

그런 다음 원하는대로 진행할 수 있습니다 myLiveData. 예를 들어 다음과 같이 $.getJSON전화를 겁니다.

$.getJSON("http://foo.bar/data.json?callback=?", function(data) {
    myLiveData.removeAll();
    /* parse the JSON data however you want, get it into myLiveData, as below */
    myLiveData.push(data[0].foo);
    myLiveData.push(data[4].bar);
});

이 작업을 완료하면 평소처럼 ViewModel을 사용하여 바인딩을 적용 할 수 있습니다.

function MyViewModel() {
    var self = this;
    self.myData = myLiveData;
};
ko.applyBindings(new MyViewModel());

그런 다음 HTML에서 myData평소 처럼 사용하십시오 .

이렇게하면 어떤 함수에서든 myLiveData를 사용할 수 있습니다. 예를 들어, 몇 초마다 업데이트하려면 해당 $.getJSON줄을 함수로 감싸고 호출 setInterval하면됩니다. myLiveData.removeAll();줄 을 유지하는 것을 기억하는 한 바인딩을 제거 할 필요가 없습니다 .

데이터가 정말 방대하지 않으면 사용자는 어레이를 재설정 한 다음 최신 데이터를 다시 추가하는 사이의 시간도 알아 차리지 못할 것입니다.


답변

나는 최근에 메모리 누수 문제가 있었고 ko.cleanNode(element);나를 위해하지 않을 것 ko.removeNode(element);입니다. Javascript + Knockout.js 메모리 누수-객체가 파괴되고 있는지 확인하는 방법은 무엇입니까?