danialfarid / ng-file-upload

Lightweight Angular directive to upload files with optional FileAPI shim for cross browser support
MIT License
7.87k stars 1.59k forks source link

slice is not a function ng-file-upload.js:489 #1139

Closed jmejiaz closed 8 years ago

jmejiaz commented 8 years ago

Uncaught TypeError: (((ngModel && ngModel.$modelValue) || attr.$$ngfPrevFiles) || []) slice is not a function

that error is throwed just after choose an image.

danialfarid commented 8 years ago

Can you post your code here? or better create a jsfiddle so we can figure out what's going wrong.

chrisschaub commented 8 years ago

Same here. Using latest build. Happens just in html, controller not involved.

danialfarid commented 8 years ago

You guys need to create a jsfiddle or describe steps to reproduce.

gwilakers commented 8 years ago

Coming across this same issue as well. Seems like @chrisschaub is correct, just happening in the html without even getting to the controller. Here is a form sample where I am seeing it:

<form class="upload-form">
  <h3 class="title">Let's add some things.</h3>
  <div class="form-group form-group-first" id="filename">
     <input class="form-input filename-input" tooltip-class="filename-tooltip" placeholder="File Name" type="text"/>
     <span tooltip class="custom-tooltip filename-tooltip">What do you want to name your file?</span>
  </div>
  <div class="form-group" id="file">
     <div class="upload-button" name="file" ngf-select ng-model="file"/>Select File</div>
  </div>
  <button class="upload-button" type="submit" ng-click="upload()">Upload</button>
</form>

Here are the versions I am using:

"dependencies": {
  "ng-file-upload": "~10.0.2",
  "jquery": "~2.1.4",
  "angular": "~1.4.7",
  "bootstrap": "~3.3.5",
  "angular-route": "~1.4.7",
  "angular-bootstrap": "~0.14.3"
}
danialfarid commented 8 years ago

That html snippet works on the demo page. Create a jsfiddle to show the error.

chrisschaub commented 8 years ago

Ok, here's the issue. The DEMO has a ng-model called "file" which is local to the form. If you create a scope variable in your controller, say $scope.data.file and try to do ng-model="data.file", you will get the slice error.

danialfarid commented 8 years ago

Did that still no error.

sean-stanley commented 8 years ago

The error is caused by the following line:

var prevFiles = (ngModel && ngModel.$modelValue || attr.$$ngfPrevFiles || []).slice(0)

This is definately a real issue though a tricky one to reproduce.

slice is undefined when prevFiles is actually trying to find a single file not an array. This happends for me after I save the result of an image upload to my database and try to replace the uploaded image afterwards.

this is a simple fix that has worked for me:

var prevFiles = (ngModel && ngModel.$modelValue && angular.isArray(ngModel.$modelValue) || attr.$$ngfPrevFiles || []).slice(0)

Just test if the existing files model is an array or not before trying to slice it.

I am not sure if this code change has any reprecussions but I'm working on a PR for it now and it's fixed my problem running a local copy of the code.

danialfarid commented 8 years ago

@sean-stanley How do you replace the server files on the client side? Unless you create a Blob object from the server data you should not replace it or assign it to the file model since it is not a file or blob.

danialfarid commented 8 years ago

I could probably add a check to detect assigning none file values to the model.

sean-stanley commented 8 years ago

Maybe I'm using the directive wrong then.

Here is what I'm doing. A picture is uploaded to cloudinary from the ngf-select directive and the request returns a bunch of useful info. On success I pass just the full url of the image on cloudinary's server as well as it's public name to the file object as 'result' and 'url' keys.

Using the ngf-src directive, I load the image from the url cloudinary returned. Then, if the user wants to replace the image with another one, they click the ngf-select directive button and select a new image. Once that is clicked, the error would occur because ng-model had a value that was not an array.

They may try and replace the image after it has been saved to the database in which case it is saved as a basic object in MongoDB not a File or Blob.

All I needed was the cloudinary url anyway as I use their service for all the resizing and stuff I need.

Would you like to see a code sample? Or a live demo? I should have a prototype live online of my app in a couple days.

danialfarid commented 8 years ago

I would try to add the logic to the plugin to ignore any non file objects in the model, but that might screw up the ngf-keep or mixing it with other directives so I might return an error if there is a non file object in the model.

For you case just use ngf-src="file || fileUrl" and save the result url of the cloudinary success in fileUrl rather than file. Or if you want to keep them together you can have an object like $scope.picture={file: file, url: cloudinaryResultUrl, data: responseData} and have ngf-select="picture.file" and ngf-src="picture.file || picture.url"

danialfarid commented 8 years ago

Should be fixed at version 10.0.3