2016-10-05 2 views
0

Вот моя проблема, с которой я борюсь.Использование наблюдаемого массива нокаута для добавления динамического элемента пользовательского интерфейса

1- Я использую плагин сопоставления для создания модели нокаута ViewModel. Со стороны сервера у меня есть сложный объект, который имеет несколько свойств (не относящихся к этому вопросу). Помимо других свойств у меня есть свойство TotalofExpenses, а также есть один список, называемый Expenses (элемент расхода - это объект, который имеет количество и описание). Mapping плагин превратить этот список в ObservableArray и TotalofExpenses в observalbe

2- На пользовательском интерфейсе я хочу достичь следующего

  • Сначала я хочу представить вход для статьи расходов. Два входных поля (один для суммы и один для описания)
  • После того, как пользователь добавит описание и сумму расходов (оба), я хочу представить поля ввода для другой статьи расходов и показать текущие расходы где-нибудь (скажем, внизу Таблица). Поскольку пользователь продолжает добавлять дополнительные расходы, я продолжаю представлять новые поля ввода и продолжать отображать итоговые суммы
  • Если пользователь вернется к ранее добавленной статье расходов и произнесет изменение, произнесите изменение суммы, которую я хочу обновить.

Ниже приведен код, которым я пытаюсь достичь описанной выше функциональности. Это НЕ работает так, как должно быть. Примечания: Я пытаюсь поставить только код, относящиеся к этой проблеме

 var data = @Html.Raw(Model.ToJson()); 
     //Add total expenses TotalShiftExpenses 
    var mappingOptionsForTotalShiftExpenses = { 
     create: function(options) { 
      return new ComputeTotalShiftExpenses(options.data); 
     } 
    }; 

    var Expense = function(data) { 
     var self = this; 
     self.ShiftId = ko.observable(@Model.Shift.Id), 
      self.Id = ko.observable(0), 
      self.Amount = ko.observable(0), 
      self.Description = ko.observable(""); 
    }   

    function ComputeTotalShiftExpenses(data) { 
     var self = this; 
     var model = ko.mapping.fromJS(data, {}, self); 
     model.TotalShiftExpenses = ko.computed(function() { 
      var sum = 0; 

      for (var i = 0; i < model.Shift.ShiftExpenses().length; i++) { 
       //     if ((parseFloat(model.Shift.ShiftExpenses()[i].Amount)) > 0) { 

       sum += parseFloat(model.Shift.ShiftExpenses()[i].Amount()); 

      } 
      //Add empty Expense to Observable array 
      if (parseFloat(model.Shift.ShiftExpenses()[ (model.Shift.ShiftExpenses().length - 1)].Amount()) > 0) { 

       model.Shift.ShiftExpenses 
        .push(new Expense({ "ShiftId": 0, "Id": 0, "Amount": 0, "Description": "" })); 

      } 

      return sum.toFixed(2); 
     }); 
     return model; 
    } 

     //Apply MappingOptions 
     var AppViewModel = ko.mapping.fromJS(data, mappingOptionsForTotalShiftExpenses); 

     $(document) 
     .ready(function() { 

      ko.applyBindings(AppViewModel); 


     }); 

С выше кодой я могу получить - первая входную коробку для первого элемента расхода - После того, как я добавляю статьи расходов, он покажет другое поле ввода, установленное для следующего элемента, а также отобразит общее количество. - Проблема заключается в том, когда я пытаюсь добавить второй расход, который он ничего не запускает (кажется, что 2-й набор полей ввода не наблюдается). Однако, если я сделаю изменение суммы в первом расходном элементе, это вызовет наблюдаемое поведение и правильно добавит элементы для обоих expesnse .. и добавит поля ввода пользовательского интерфейса для 3-го расхода. По какой-то причине всегда последнее поле ввода не вызывает наблюдаемое поведение, но любое поле перед последним будет делать. Примечание. Код, который я опубликовал, только пытается добавить сумму расходов.

Отчаянно ожидая услышать от эксперта по нокауту .... большое спасибо заранее.

ответ

0

Он смотрит на меня, как у вас есть более-сложные вещи немного. На самом деле должно быть очень просто сопоставить данные и создать вычисленное наблюдаемое, которое отслеживает общую сумму:

Редактировать: Обновлено, чтобы включить функциональность динамического ввода.Вы можете сделать это, добавив несколько строк кода, чтобы вычисленная наблюдаемым, чтобы гарантировать, что пустой элемент всегда существует в нижней части массива:

// Data pulled in from wherever 
var data = [{ 
    ShiftId: 1, 
    Id: 1, 
    Amount: 25.00, 
    Description: 'Supplies' 
}, { 
    ShiftId: 2, 
    Id: 2, 
    Amount: 20.00, 
    Description: 'Lunch' 
}]; 

// Expense model 
var Expense = function(shiftId, id, amount, desc) { 
    var self = this; 
    self.ShiftId = ko.observable(shiftId); 
    self.Id = ko.observable(id); 
    self.Amount = ko.observable(amount); 
    self.Description = ko.observable(desc); 
}; 

// Main ViewModel 
var AppViewModel = function() { 
    var self = this; 

    // Expenses array 
    self.Expenses = ko.mapping.fromJS(data); 

    // Compute the grand total of all expenses 
    self.TotalofExpenses = ko.computed(function() { 
    // First, ensure that a blank item remains at the bottom of array 
    self.Expenses.remove(function(item) { 
     return !item.Amount() && !item.Description(); 
    }); 
    self.Expenses.push(new Expense()); 

    // Now calculate the sum of all expenses 
    var total = 0; 
    self.Expenses().forEach(function(item, index) { 
     total += +item.Amount() || 0; 
    }); 

    return total; 
    }); 
}; 

ko.applyBindings(new AppViewModel()); 

Edit 2: пересматриваемых JSFiddle так, что вход Сумма коробки отключены, пока пользователь не предоставит значение для ввода описания (см. HTML в ссылке JSFiddle). Я сделал это, просто добавив «enable: Description» к привязке для поля ввода суммы.

https://jsfiddle.net/dw1284/aaysdxmb/9/

+0

Большое спасибо за вашу помощь. Однако то, что вы опубликовали, уже работает для меня. Моя проблема заключается в том, чтобы добавить динамические поля ввода и получить их общее количество. Не могли бы вы добавить эту функциональность в свое решение. Большое спасибо. –

+0

Ответ был обновлен, чтобы включить динамическое добавление и удаление элементов формы, когда пользователь вводит данные. –

+0

Спасибо, миллион. На самом деле я не могу сказать Спасибо. Я отметил это как ответ. Если вы можете добавить небольшое обновление, я по достоинству оценят его. Если вы можете сделать так, описание должно быть введено до того, как сумма будет введена. –

0

Так, основываясь на том, что вы сказали, я создал простую скрипку, где количество полей ввода контролируется ko.observableArray и привязкой foreach. Когда вы добавляете или удаляете (удаляете не скрипку) элементы из массива, просмотр автоматически обновляется. В вашем случае кажется, что есть больше функциональности и других специальных проверок, которые вы хотите сделать, но я считаю, что это должно помочь вам с тем, что вы пытаетесь выполнить.

JSFiddle

function TestVM() { 
 
    this.inputFields = ko.observableArray([ 
 
    { type: 'type1', displayName: 'name1' }, 
 
    { type: 'type2', displayName: 'name2' }, 
 
    { type: 'type3', displayName: 'name3' } 
 
    ]); 
 
} 
 

 
var dynamic = new TestVM(); 
 
ko.applyBindings(dynamic); 
 

 
$('#addInput').click(function(){ 
 
dynamic.inputFields.push({ type: 'newtype', displayName: 'newField' }); 
 
    console.log(dynamic.inputFields()); 
 
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 

 
<div> 
 
    <div data-bind="foreach: inputFields"> 
 
    <label data-bind="text: $data.displayName"></label><br> 
 
    <input data-bind="name: $data.type"><br> 
 
    </div> 
 
</div> 
 

 
<button id="addInput">Add</button>

+0

Большое спасибо моему другу. Я видел твою скрипку. Я хочу добавить новое поле ввода без нажатия кнопки. Более того, я также хочу иметь общее количество всех сумм, введенных в поля ввода. –

+1

Правильно, вот что я имел в виду, все, что вам нужно сделать за кулисами, это добавить к этому массиву, а не как его привязать к событию клика. Щелчок на кнопке был просто инициатором добавления новых кнопок в этом примере. Что касается текущих сумм в привязке, просто добавьте привязку текста к foreach в представлении (http://knockoutjs.com/documentation/text-binding.html). –