CanJS - Управляющая связь

Сейчас я изучаю CanJS, поэтому я хочу попробовать очень простую небольшую демонстрацию. Демонстрация: у вас будут разные типы мобильных тарифных планов, которые отображаются вверху (переключатели), и при выборе каждого плана соответствующие ценовые опции будут отображаться в таблице внизу.

Для этой демонстрации я создаю два файла Model, 2 Control и 2 Template, мой вопрос: как два элемента управления могут общаться друг с другом? Какой стандартный способ?

Сейчас я напрямую вызываю метод управления через его экземпляр, но я не уверен, что это правильный способ. Также, пожалуйста, объясните Can.Route.

Вывод http://jsfiddle.net/sabhab1/2mxfT/10/

Данные

var CATEGORIES = [{id: 1 , name: "2G Internet Recharge"},
                  {id: 2 , name: "3G Internet Recharge"},
                  {id: 3 , name: "full talktime Recharge"},
                  {id: 4 , name: "Validity and talktime Recharge"},
                  {id: 5 , name: "National and international roaming"}];
var RECHARGEAMOUNTS =[{
                       id: 1 , 
                       values : [{amount: "Rs. 100" , benefit:"300 MB" ,validity:"30"},
                                 {amount: "Rs. 200" , benefit:"1 GB" ,validity:"30"}]
                       },
                       {
                       id: 2 , 
                       values : [{amount: "Rs. 10" , benefit:"300 MB" ,validity:"30"},
                                 {amount: "Rs. 99" , benefit:"100 GB" ,validity:"90"}]
                       },
                       {
                       id: 3 , 
                       values : [{amount: "Rs. 80" , benefit:"1 GB" ,validity:"50"},
                                 {amount: "Rs. 99" , benefit:"100 GB" ,validity:"50"}]
                       },
                       {
                       id: 4 , 
                       values : [{amount: "Rs. 55" , benefit:"30 MB" ,validity:"10"},
                                 {amount: "Rs. 200" , benefit:"1 GB" ,validity:"30"},
                                 {amount: "Rs. 99" , benefit:"100 GB" ,validity:"90"}]
                       },
                       {
                       id: 5 , 
                       values : [{amount: "Rs. 880" , benefit:"100 MB" ,validity:"90"},
                                 {amount: "Rs. 550" , benefit:"2 GB" ,validity:"30"},
                                 {amount: "Rs. 1000" , benefit:"4 GB" ,validity:"90"},
                                 {amount: "Rs. 1550" , benefit:"10 GB" ,validity:"90"}]
                       }
                     ]; 

модель

//Model Category
CategoryModel = can.Model({
  findAll : function(){
      return $.Deferred().resolve(CATEGORIES);
    }
},{});

//Model Category
ReachargeAmountModel = can.Model({
    findAll : function(){
      return $.Deferred().resolve(RECHARGEAMOUNTS);
    },
    findOne : function(params){
      return $.Deferred().resolve(RECHARGEAMOUNTS[(+params.id)-1]);
    }
},{});

контроль

**// Can Control 
var CategoryControl = can.Control({
    // called when a new Todos() is created
    init: function (element, options) {
        // get all todos and render them with
        // a template in the element's html
        var el = this.element;
        CategoryModel.findAll({}, function (values) {
            el.html(can.view('categoriesEJS', values))
        });
        this.options.rchAmtCtrl = new RechargeAmountControl("#rechnageAmountView"); 
    },
    'input click' : function( el, ev ) {
        var id = el.data('category').attr('id');
        console.log(id);
        this.options.rchAmtCtrl.update(id);
    }

});
// Can Control 
var RechargeAmountControl = can.Control({
    // called when a new Todos() is created
    init: function (element, options) {
        // get all todos and render them with
        // a template in the element's html
        this.update(1);//this.update(id,this.element);
    },
    update : function(id){
        var el = this.element;
        ReachargeAmountModel.findOne({id: id}, function( rechargeAmount ){
            // print out the todo name
            //console.log(rechargeAmount.values[id].attr('benefit'));
            el.html(can.view('RechnageAmountEJS', rechargeAmount.values));
        });
    }
});**

Посмотреть

<form id='categoriesView'></form>
</p>
<table id='rechnageAmountView'></table>
<script type='text/ejs' id='RechnageAmountEJS'>
    <tr>
        <th>Recharge Amount</th>
        <th>Benefits</th>
        <th>Validity(Days)</th>
    </tr>
    <% this.each(function( rechargeAmount ) { %>
        <tr>
            <td>
                <%= rechargeAmount.attr( 'amount' ) %>
            </td>   
            <td>
                <%= rechargeAmount.attr( 'benefit' ) %>
            </td>   
            <td>
                <%= rechargeAmount.attr( 'validity' ) %>
            </td> 
        </tr>   
    <% }) %>

 </script>

<script type='text/ejs' id='categoriesEJS'>
    <% this.each(function( category ) { %>
        <input type="radio" 
            name="category" 
            <%= category.attr('id') == 1 ? 'checked' : '' %>
            value=<%= category.attr( 'name' ) %> 
            <%= (el) -> el.data('category',category) %>>
                <%= category.attr( 'name' ) %>
        </input>    
    <% }) %>
</script>

Главный звонок

new CategoryControl("#categoriesView");     

1 ответ

Решение

Есть несколько способов сделать это.

1. Вызов методов напрямую

Это то, что вы делаете, и это не обязательно неправильно. Чтобы сделать вещи немного более гибкими, вы можете передать класс или экземпляр RechargeAmountControl при инициализации CategoryControl вместо того, чтобы использовать его напрямую.

2. DOM события

Здесь речь пойдет немного о событийно-ориентированной архитектуре. Если вы обычно хотите уведомить другие элементы управления, вы можете просто вызвать любое событие и заставить их прослушать его. Примерно так: http://jsfiddle.net/2mxfT/11/

' rechargeAmountUpdated': function(element, event, id){
    var el = this.element;
    console.log(arguments);
    ReachargeAmountModel.findOne({id: id}, function( rechargeAmount ){
        // print out the todo name
        //console.log(rechargeAmount.values[id].attr('benefit'));
        el.html(can.view('RechnageAmountEJS', rechargeAmount.values));
    });
}

3. Наблюдаемые

Другой вариант - использовать Observables для поддержания общего состояния. Это отличный способ сфокусироваться на данных и позволить всему остальному сделать привязку в реальном времени. Чтобы сделать вещи более гибкими, объект состояния должен быть передан во время инициализации Control (см. http://jsfiddle.net/2mxfT/12/):

var state = new can.Observe();

new RechargeAmountControl("#rechnageAmountView", {
    state: state
}); 
new CategoryControl("#categoriesView", {
    state: state
});

state.attr('rechargeId', 1);

И тогда вы можете просто прослушать изменения атрибутов в RechargeAmountControl следующим образом:

'{state} rechargeId': function(Construct, event, id){}

Этот обработчик будет вызываться всякий раз, когда вы обновляете состояние Observe.

И это также, где can.route приходит. В основном can.route - это Observ, который сохраняет свое состояние в хеше местоположения. В приведенном выше примере, как #!&rechargeId=1 (если вы не инициализируете конкретный маршрут как can.route(':rechargeId')). Если хэш местоположения изменится, Наблюдение будет обновлено, и наоборот.

Другие вопросы по тегам