2014-02-11 3 views
-1

내 viewmodel 데이터를 하이 차트 차트에 바인딩하는 사용자 지정 바인딩 처리기를 작성했습니다. 이것은 실제로 2 부분으로 구성되며, 하나는 하이 차트에 필요한 초기 구성을 바인딩하고, 두 번째 부분은 차트에 시리즈를 바인딩합니다. 여기 예기치 않게 사용자 지정 녹아웃 바인딩이 두 번 발생합니다.

지금 나는이에 대한 설정이 개 테스트를 가지고있는 bindingHandler 코드

ko.bindingHandlers.highchart = { 
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
     var value = valueAccessor(); 
     var valueUnwrapped = ko.unwrap(value); 
     console.log ('update',element.id,valueUnwrapped);   
     if(allBindings.get('series')){ 
      var series = allBindings.get('series'); 
      var seriesUnwrapped = ko.unwrap(series); 
      if(!$.isArray(seriesUnwrapped)){ 
       seriesUnwrapped = [seriesUnwrapped]; 
      } 
      console.log('seriesUnwrapped',element.id,seriesUnwrapped) 
      valueUnwrapped.series = seriesUnwrapped; 
     } 
     $(element).highcharts(valueUnwrapped);   
    } 
} 

이며, 첫 번째 작품은 예상대로. 여러 계열의 차트를 바인딩하고 series에 바인딩 된 관찰 가능 배열에 추가하면 차트가 한 번만 업데이트됩니다. this fiddle을보고 콘솔에서 "추가"버튼을 클릭하십시오. 당신이 얻을 것이다 출력은

업데이트 컨테이너 개체입니다 {차트 = {...}}
seriesUnwrapped 컨테이너 [오브젝트 {이름 = "Scenario0"색상 = "빨간색"데이터 = [9]}

우리는 위의 코드를 한 번만 사용했다는 것을 나타냅니다. Object {name = "Scenario1", color = "green", data = [9]}

이제 두 번째 바이올린을 확인하십시오 : http://jsfiddle.net/8j6e5/9/. 이것은 하이 차트의 초기 설정이 관찰 할 수있는 것처럼 computed이며 시리즈와 약간 다릅니다. [=

업데이트 컨테이너 2 개체 {차트 = {...}, x 축이 = {...} 시리즈 :이 하나에 "추가"버튼을 클릭하면 바인딩 두 번 실행됩니다를 볼 수 있습니다 1]}
seriesUnwrapped container2 [object {name = "Scenario2", color = "blue", data = [2]}
업데이트 container2 개체 {chart = {...}, xAxis = {...} }
seriesUnwrapped 컨테이너 2 [오브젝트 {이름 = "시나리오 2", 색상 = "파란색"데이터 = [2]}]

내 highcharts 내 allBindings.get('series')를 사용하여 바인딩 핸들러 내가 설정 같은데요 의존성을 높이고, 두 바인딩 모두 하이 차트 바인딩을 두 번 바꿀 때. 내 질문은, 거기 에이 방법을 멈추거나,이 다른 어떤 방식 으로이 일을하지 않는이 기능을 쓸 수 있습니까?

+1

업데이트 기능을 호출 할시기를 결정해야합니다. 그래서 바운드 프로퍼티가 변경되거나'series' 바운드 프로퍼티가 변경 될 때. 그리고 나서'ko.unwrap' 대신'peek()'을 사용하십시오 :'var seriesUnwrapped = series.peek();'또는'var valueUnwrapped = value.peek();'물론' value '또는'series'는 실제로 peek을 호출하기 전에 관찰 할 수 있습니다. – nemesv

+0

@nemesv - 아주 좋은 시작인데, 그게 홀 호출 문제를 해결 한 것뿐입니다. 그러나 간단한 변경을 한 후에는 첫 번째 바이올린이 더 이상 업데이트되지 않습니다 (계산 된 시리즈에 바인딩되어 있지만 정적 하이 차트 속성에 바인딩 됨). 당신은 2/3의 아주 좋은 대답을하고 있습니다. – Jamiec

+1

'var valueUnwrapped = ko.isObservable (value)'값을 사용하면? value.peek() : value;'둘 다 수정됩니다. 그러나 바인딩이'highchart : yourProp, series : otherProp'이고'yourProp'만이 변경되고'otherProp'가 다시 안되면 차트가 올바르게 업데이트되지 않습니다 ... – nemesv

답변

3

위의 설명에있는 nemesv 대답이 달성하고자하는 것과 매우 근접해 보이는 것처럼 이것이 도움이 될지 확신하지 못합니다. 이중 업데이트를 중지합니다.

그러나 나는 그것에 대해 약간의 시간을 보냈으므로 어쨌든 내가 생각한 것을 보여주고 도움이 되길 바랍니다.

Fiddle here

내가 언급 nemesv 픽() 메소드 (좋은 팁)에 대해 알고하지 않았다, 그래서 그것을 두 번 나는 것을보고

computeds 등을 기준으로하여 갱신을 이유로 보았다 self.breakdownChart는 currentScenario observable에 액세스하고 있었고 테스트로 제거하면 두 번째 업데이트가 발생하지 않았습니다.

이렇게 생각해 봤는데 왜 x 축 설정이 필요 했나요?

그래서 나는 그리고 기본 시나리오, 그 제목이 그냥 시리즈에 대해 올바르게 표시하기 위해이를 "기본 시나리오"로 변경

self.name='Scenario' + self.number; 

현재 시나리오 이름을 반환하는 시나리오에 새로운 속성을 추가 .

나는
self.breakdownChart = ko.computed(function(){ 
    return {  
     baseSeriesTitle: baseScenario.name, 

baseSeriesName

라는 차트 개체에 새로운 속성을 추가하고이 baseScenario의 이름으로 설정됩니다, 전설/축이 정확한지 확인하십시오.

마지막으로, 내가 거기에서 x 축 업데이트는 BindingHandler에 모두 함께 그 넥타이 :

 //set the xAxis titles, only add the second title if different from the base 
     valueUnwrapped.xAxis={ 
      categories: [valueUnwrapped.baseSeriesTitle, valueUnwrapped.baseSeriesTitle!=seriesUnwrapped[0].name ? seriesUnwrapped[0].name:''] 
     } 

그것은 리팩토링의 비트,하지만 당신의 목표를 달성; 도움이되기를 바랍니다.

아, 또한 뷰 모델에 관찰 가능 유형을 추가하고 차트 정의 (breakdownChart calculated)에 사용하여 다른 관찰 가능 항목에서 차트를 새로 고치면 여전히 이중 업데이트를 테스트합니다. 정확하게 초기화 됨 - 바이올린은 double 업데이트없이 chartType 업데이트를 보여줍니다.

3

Knockout은 종속성이 변경 될 때 Observable을 즉시 업데이트하고 바인딩에 두 개의 종속성이있을 때 두 개의 업데이트가 생성됩니다. 각 종속성은 순서대로 업데이트됩니다.

이 문제를 해결하는 한 가지 방법은 바인딩 업데이트를 지연시키는 기술을 사용하는 것입니다. http://jsfiddle.net/mbest/8j6e5/15/

이연 업데이트는 업데이트가 비동기 적으로 발생한다는 것을 의미하는 업데이트를 수행 할 수 setTimeout를 사용하여 여기에 입증 된 바와 같이 그렇게하는 쉬운 방법은 Deferred Updates plugin을 사용하는 것입니다. 특정 업데이트에 대해 동기화하려는 경우 ko.tasks.processImmediate을 사용할 수 있습니다.

ko.tasks.processImmediate(function() { 
    self.scenarios.push(newScenario); 
    self.currentScenario(newScenario); 
});