Как получить доступ к вводу файлов с привязкой к нокауту?

С учетом следующего кода:

<input data-bind="event: { change: uploadImage(this.files[0]) }" style="width: 10px;" type="file">

Я получаю сообщение об ошибке "файлы не определены". Я пытаюсь преобразовать это демо:

https://github.com/paulrouget/miniuploader/blob/gh-pages/index.html

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

jsfiddle: http://jsfiddle.net/LkqTU/9597/

Ответы

Ответ 1

У вас есть две проблемы:

  • если вы просто напишите вызов функции (uploadImage(this.files[0])) внутри литерала объекта, он будет выполнен один раз, когда литерал объекта инициализируется, поэтому, когда KO анализирует привязку. Таким образом, он будет выполнен один раз с неправильными аргументами, и вы измените событие не будет работать. Вы можете заставить его работать с завершением его в анонимную функцию. См. Документацию Доступ к объекту события или передача большего количества параметров.

  • this не ссылается на текущий элемент в привязке, который вам нужно использовать $element.

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

data-bind="event: { change: function() { uploadImage($element.files[0]) } }"

Демо JSFiddle.

Ответ 2

Для всех, кого это интересует, вы можете использовать следующую настраиваемую привязку, которая позволяет привязать элемент ввода файла к наблюдаемому нокауту, содержащему File.

Он обрабатывает установку наблюдаемого на выбранный файл (как указано в @nemesv), а также очищает входной элемент, когда для наблюдаемого задано значение null (см. this ответ):

ko.bindingHandlers.fileUpload = {
    init: function (element, valueAccessor) {
        $(element).change(function () {
            valueAccessor()(element.files[0]);
        });
    },
    update: function (element, valueAccessor) {
        if (ko.unwrap(valueAccessor()) === null) {
            $(element).wrap('<form>').closest('form').get(0).reset();
            $(element).unwrap();
        }
    }
};

Пример:

function Example() {
  var self = this;

  self.uploadFile = ko.observable(null);
  self.uploadName = ko.computed(function() {
    return !!self.uploadFile() ? self.uploadFile().name : '-';
  });

  self.clear = function() {
    self.uploadFile(null);
  };
};

ko.bindingHandlers.fileUpload = {
  init: function(element, valueAccessor) {
    $(element).change(function() {
      valueAccessor()(element.files[0]);
    });
  },
  update: function(element, valueAccessor) {
    if (ko.unwrap(valueAccessor()) === null) {
      $(element).wrap('<form>').closest('form').get(0).reset();
      $(element).unwrap();
    }
  }
};

ko.applyBindings(new Example());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<input type="file" data-bind="fileUpload: uploadFile">
<br/>
<br/>Selected file name: <span data-bind="text: uploadName"></span>
<br/>
<button data-bind="click: clear">Clear input</button>