Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to upload image and save it in database using knockout js?

hey m using mvc3 with knockout and trying to use knockout binding to upload and save uploaded image in database. i am able to browse and get the image but not getting as how to save that image. my html view is:

<div data-bind="foreach: { data: images, beforeRemove: beforeRemoveSlot }">
        <div>
            <input type="file" accept="image/*" data-bind="file: imageFile, fileObjectURL: imageObjectURL, fileBinaryData: imageBinary"/>
            <div data-bind="if: imageObjectURL">
                <img class="thumb" data-bind="attr: { src: imageObjectURL }"/>
            </div>
            <div>Size: <span data-bind="text: fileSize"></span>&nbsp;bytes</div>
        </div>
    </div>
        <input type="submit" value="Upload Picture" data-bind="click: upload" />

my view model is:

var windowURL = window.URL || window.webkitURL;

ko.bindingHandlers.file = {
    init: function (element, valueAccessor) {
        $(element).change(function () {
            var file = this.files[0];
            if (ko.isObservable(valueAccessor())) {
                valueAccessor()(file);
            }
        });
    },

    update: function (element, valueAccessor, allBindingsAccessor) {
        var file = ko.utils.unwrapObservable(valueAccessor());
        var bindings = allBindingsAccessor();

        if (bindings.fileObjectURL && ko.isObservable(bindings.fileObjectURL)) {
            var oldUrl = bindings.fileObjectURL();
            if (oldUrl) {
                windowURL.revokeObjectURL(oldUrl);
            }
            bindings.fileObjectURL(file && windowURL.createObjectURL(file));
        }

        if (bindings.fileBinaryData && ko.isObservable(bindings.fileBinaryData)) {
            if (!file) {
                bindings.fileBinaryData(null);
            } else {
                var reader = new FileReader();
                reader.onload = function (e) {
                    bindings.fileBinaryData(e.target.result);
                };
                reader.readAsArrayBuffer(file);
            }
        }
    }
};

var imageUploadModel = function () {
    var self = {};

    var slotModel = function () {
        var that = {};

        that.imageFile = ko.observable();
        that.imageObjectURL = ko.observable();
        that.imageBinary = ko.observable();

        that.fileSize = ko.computed(function () {
            var file = this.imageFile();
            return file ? file.size : 0;
        }, that);

        that.firstBytes = ko.computed(function () {
            if (that.imageBinary()) {
                var buf = new Uint8Array(that.imageBinary());
                var bytes = [];
                for (var i = 0; i < Math.min(10, buf.length); ++i) {
                    bytes.push(buf[i]);
                }
                return '[' + bytes.join(', ') + ']';
            } else {
                return '';
            }
        }, that);

        return that;
    };

    self.beforeRemoveSlot = function (element, index, data) {
        if (data.imageObjectURL()) {
            windowURL.revokeObjectURL(data.imageObjectURL());
        }
        $(element).remove();
    };

    self.images = ko.observableArray([slotModel()]);

    self.addSlot = function () {
        self.images.push(slotModel());
    };

    self.removeSlot = function (data) {
        self.images.remove(data);
    };

    return self;
} ();

imageUploadModel.upload = function () {

}

$(document).ready(function () {
    ko.applyBindings(imageUploadModel);
});

can anybody suggest me how can i save image on upload button click?????

like image 876
Parasignals Avatar asked Nov 07 '12 07:11

Parasignals


1 Answers

here's an example of single click image uploads via knockout I've scrubbed together

html ->

<input type="file" data-bind="value: fileName, fileUpload: fileName, url: url">
<script src="{{ STATIC_URL }}html5knockoutImagePreview.js"></script>​

js ->

ko.bindingHandlers.fileUpload = {

update: function(element, valueAccessor, allBindingsAccessor){
        var value = ko.utils.unwrapObservable(valueAccessor())
        if(element.files.length && value){
        var file = element.files[0];
        var url = allBindingsAccessor().url

        xhr = new XMLHttpRequest();
        xhr.open("post", url, true);
        xhr.setRequestHeader("Content-Type", "image/jpeg");
        xhr.setRequestHeader("X-File-Name", file.name);
        xhr.setRequestHeader("X-File-Size", file.size);
        xhr.setRequestHeader("X-File-Type", file.type);
        console.log("sending")
        // Send the file (doh)
        xhr.send(file);
        }
  }
}


function MainPageViewModal(){
  this.fileName = ko.observable()
  this.url = "http://127.0.0.1:8000/upload"
}

var mainPageViewModal = new MainPageViewModal()

ko.applyBindings(mainPageViewModal);

fiddle

I'm not 100% sure of all your requirements, this is for jpegs, you need to tweak the content type header for other types etc.

Edit

As you're continuing to have issues, here's some code that I've written since then that might help. It does use jquery though...

ko bindings ->

ko.bindingHandlers.filePreview = {
  update: function(element, valueAccessor, allBindingsAccessor){
      var allBindings = allBindingsAccessor()
      if(!!FileReader && valueAccessor() && element.files.length){
        var reader = new FileReader();
        reader.onload = function(event){
          var dataUri = event.target.result
          allBindings.imagePreview(dataUri)
        }
        reader.onerror = function(e) {
          console.log("error", stuff)
        }
        reader.readAsDataURL(element.files[0])
    }
  }
}

modelPageView ->

, uploadPreview: function(files){
        var self = this
        self.loadingPreview(true)
        file = files[0]
        if(file.size > 20000000){
          alert("that image is a bit too big for us, got anything smaller?")
        }
        console.log("file size " + file.size)
        var formData = new FormData();
        formData.append("img", file)
        $.ajax({
          url: "/YOUR_UPLOAD_URL",
          type: 'POST',
          data: formData,
          cache: false,
          contentType: false,
          processData: false
      }).done(function(data){
         if(data === "error"){
           alert("somethign wrong happened, please refresh the page")
           return
         }
         self.imgUrl(data.img_url)
         self.imgId(data.img_id)
      }).fail(function(){
        self.loadingPreview(false)
      })
}

html ->

<input type="file" accept="image/*" name="img" data-bind="value: img, fileAdded: img, previewFunc: function(files){ $data.uploadPreview(files) }" />
  • The advantages of this method is a lot of frameworks like form data rather than just image content-type data better.
  • Personally I think server side interaction should be driven by the backend modal so that's why the code's there rather than in the binding handler.
  • You also get the magic of the jquery ajax object if you need it.

Sorry about the delay in replying, I'll take a peak in a couple of days, so let me know if you're still having issues.

Good Luck!

like image 190
Fred Avatar answered Oct 16 '22 17:10

Fred