2016-06-08 5 views
3

Я пытаюсь использовать генератор KnockoutJS SPA Yeoman для создания приложения SPA и использования плагина ko.mapping. Я скорректировал require.config.js, чтобы включить ko-mapping.Использование ko.mapping с компонентами нокаута в SPA

В автономном приложении я могу заставить плагин сопоставления работать нормально, но когда я пытаюсь использовать его в построенной функции компонента, привязки никогда не будут доступны в шаблоне html. Любые идеи о том, что я могу сделать неправильно, чтобы получить плагин отображения для воспроизведения в компоненте KO?

var require = { 
    baseUrl: ".", 
    paths: { 
     "bootstrap":   "bower_modules/components-bootstrap/js/bootstrap.min", 
     "crossroads":   "bower_modules/crossroads/dist/crossroads.min", 
     "hasher":    "bower_modules/hasher/dist/js/hasher.min", 
     "jquery":    "bower_modules/jquery/dist/jquery", 
     "knockout":    "bower_modules/knockout/dist/knockout", 
     "komapping":   "bower_modules/knockout-mapping/knockout.mapping", 
     "knockout-projections": "bower_modules/knockout-projections/dist/knockout-projections", 
     "signals":    "bower_modules/js-signals/dist/signals.min", 
     "text":     "bower_modules/requirejs-text/text" 
    }, 
    shim: { 
     "bootstrap": { deps: ["jquery"] }, 
     "komapping": { deps: ["knockout"], exports: 'komapping'} 
    } 
}; 

define(['jquery', 'knockout', './router', 'bootstrap', 'knockout-projections'], function($, ko, router) { 
     // Components can be packaged as AMD modules, such as the following: 
     ko.components.register('nav-bar', { require: 'components/nav-bar/nav-bar' }); 
     ko.components.register('home-page', { require: 'components/home-page/home' }); 

     // ... or for template-only components, you can just point to a .html file directly: 
     ko.components.register('about-page', { 
     template: { require: 'text!components/about-page/about.html' } 
     }); 

     ko.components.register('bems', { require: 'components/bems/bems' }); 
     ko.components.register('user-page', { require: 'components/user-page/user' }); 
     ko.components.register('team-page', { require: 'components/team-page/team' }); 
     ko.components.register('exec-page', { require: 'components/exec-page/exec' }); 

     // [Scaffolded component registrations will be inserted here. To retain this feature, don't remove this comment.] 

     // Start the application 
     ko.applyBindings({ route: router.currentRoute }); 
}); 

define(['knockout', 'text!./bems.html','komapping'], function(ko, templateMarkup, komapping) { 
    function Bems(params) { 
     ko.mapping = komapping; 
     var self = this; 
     self.response = ko.observable(); 

     if (typeof params[0] != 'undefined') { 
      // Suppress search while loading 
      document.getElementById("bems-input").style.visibility = "hidden"; 
      self.bemsId = String(params[0]); 

      $.ajaxSetup({ 
      cache: false, 
      "error":function() { 
       document.getElementById("bems-input").style.visibility = "visible"; 
       window.location = ("#/bems/"); 
      } 
      }); 

      $.getJSON('/app/skyline/api/bems/' + self.bemsId, function(ajax_response) { 
       document.getElementById("bems-input").align = "right"; 
       document.getElementById("bems-input").style.visibility = "visible"; 
       document.getElementById("bems-container").style.visibility = "visible"; 
       ko.mapping.fromJS(ajax_response, {}, self.response); 
      }); 
     } 
     // Nothing to do without bemsId parameter 
    } 

    return { viewModel: Bems, template: templateMarkup }; 
}); 

Я также протестирована со следующими изменениями:

self.response = ko.observable(); 
self.message = ko.observable("It works"); 

$.getJSON('/app/skyline/api/bems/' + self.bemsId, function(ajax_response) { 
    self.response = ko.mapping.fromJS(ajax_response); 

В выше self.message связывает должным образом, и могут быть доступны в шаблоне. Однако сопоставленные атрибуты в self.response не связаны.

Ключевое различие между моей рабочей установкой и сломанным случаем находится в рабочем примере. Я установил результат ko.mapping во всю переменную модели представления, где здесь функция Bems - это модель представления, и это переменная под Vm.

Я еще раз взглянул на это сегодня и приблизился к проблеме. Похоже, что основной проблемой является порядок операций между обработкой обратного вызова AJAX и привязкой, происходящей через инфраструктуру приложения компонента Yoeman. Если я сделаю следующее и поставлю 2-секундную задержку в главном ViewModel, ему удастся загрузить содержимое привязки для первого атрибута привязки в представлении, но затем все равно будет умирать с помощью TypeError, даже если данные загрузились для атрибута. Это останавливает скрипт, и никакие другие атрибуты не загружаются.

require.js:900 TypeError: Unable to process binding "text: function(){return response().engagement_list()[0].CASE_TITLE }"(…) 

function BemsViewModel(params) { 

self.response = ko.observable(); 

     $.getJSON('/app/skyline/api/bems/' + self.bemsId(),   function(ajax_response) { 
      $("#bems-input").attr("align","right"); 
      $("#bems-input").attr("style", "visibility: visible") 
      $("#bems-container").attr("style", "visibility: visible") 
      var foobar = {}; 
      ko.mapping.fromJS(ajax_response, {}, foobar); 
      self.response(foobar); 

Есть ли лучшая практика/шаблон для обеспечения связывания происходит только после того, как все биты модели представления загружаются с помощью этого шаблона KO компонент SSA? Любая помощь/идеи будут оценены. Я действительно не хочу вручную определять всю модель представления ...

ответ

1

Хорошо, теперь у меня это работает. Ключ должен сделать выше, если вы правильно добавили сопоставленные атрибуты в существующую модель представления, но также должны использовать привязку данных с атрибутом для сопоставления этого динамического содержимого. Таким образом, функция ko.binding работает только до верхнего уровня и не жалуется на отсутствующие атрибуты ниже. Поскольку эти load asyc после того, как viewmodel уже привязан, эти данные будут заполняться после факта.

http://knockoutjs.com/documentation/with-binding.html

<div id="bems-dyn" data-bind="with: response"> 
<p>BEMS Title: <span data-bind="text: engagement_list()[0].CASE"></span></p> 
<p>Container Type: <span data-bind="text: global_params.container_type"></span></p> 
<p>BEMS Id: <span data-bind="text: global_params.bems_id"></span></p> 
</div> 

self.response = ko.observable(); 

    $.getJSON('/app/test/api/bems/' + self.bemsId(), function(ajax_response) { 
     $("#bems-input").attr("align","right"); 
     $("#bems-input").attr("style", "visibility: visible") 
     $("#bems-container").attr("style", "visibility: visible") 
     //self.response = ko.mapping.fromJS(ajax_response); 
     var foobar = {}; 
     ko.mapping.fromJS(ajax_response, {}, foobar); 
     self.response(foobar); 
Смежные вопросы