.controller('ImageChangeController', function($scope, $http, $element){
$scope.itemid = '';
reader = new FileReader();
file_inputs = $element.children('.img-change');
img_doc = $element.children('img').get(0);
file_inputs.change(function(e){
reader.onload = function(e) {
img_doc.src = e.target.result;
}
$scope.itemid = "999"; //does not work
});
$scope.change_name = function(){
$scope.itemid = "999";
}
here is my template code:
<div ng-controller="ImageChangeController">
<span>{{itemid}}</span>
<input type="file" class="img-change" name="{{itemid}}" accept="image/*">
</div>
if I change itemid through ng-click="change_itemid()", it will be work well.
Basically, you should use angular directives instead of non-native elements:
http://ngmodules.org/modules/ng-file-upload
If you want to solve problem without changing the implementation (for example, the direcitve does not give you feature you want):
The problem source is this part of code:
file_inputs.change(function(e){
reader.onload = function(e) {
img_doc.src = e.target.result;
}
$scope.itemid = "999"; //does not work
});
the function is called outside the angular digest cycle. You should inform angular about changes:
file_inputs.change(function(e){
reader.onload = function(e) {
img_doc.src = e.target.result;
$scope.$applyAsync();
}
$scope.itemid = "999"; //does not work
$scope.$applyAsync();
});
Related
I'm currently trying create a drag and drop file uploader with the standard option to just use the regular input. I'm not sure what to be targeting to write if the user clicked the upload or dropped a file in.
My first thought was to check if the FileList is empty but both ways produce a FileList. Second thought was just write two functions one for the input and one for the drop but that seems like I would be repeating. Last thought was writing an if statement in the read_file function. However, I'm not sure what to target exactly.
Any ideas would be greatly appreciated!! thanks!!
https://jsfiddle.net/nick1572/b4xzt8oh/3/
var uploader = document.querySelector('.uploader');
var output = document.getElementById('output');
var file = document.getElementById('file');
file.addEventListener('change', function(event) {
read_file(event);
});
function read_file(event) {
file = event.target;
var reader = new FileReader();
reader.onload = function() {
var data_url = reader.result;
output.src = data_url;
};
// This will read when the image is dropped.
//reader.readAsDataURL(event.dataTransfer.files[0]);
reader.readAsDataURL(file.files[0]);
/*
Something like this
if () {
reader.readAsDataURL(file.files[0]);
} else if() {
reader.readAsDataURL(event.dataTransfer.files[0]);
}
*/
};
uploader.addEventListener('dragover', function(e) {
console.log('drag over');
e.preventDefault();
});
uploader.addEventListener('dragenter', function(e) {
console.log('drag enter');
e.preventDefault();
});
uploader.addEventListener('dragleave', function() {
console.log('drag leave');
});
uploader.addEventListener('drop', function(event) {
console.log('drop');
event.preventDefault();
read_file(event);
});
Check the type property of the event object to see which event has been used.
function read_file(event) {
file = event.target;
var reader = new FileReader();
reader.onload = function() {
var data_url = reader.result;
output.src = data_url;
};
if (event.type === 'change') {
reader.readAsDataURL(file.files[0]);
} else if(event.type === 'drop') {
reader.readAsDataURL(event.dataTransfer.files[0]);
}
};
I'm making a typical drag and drop for upload images from desktop to browser, i can drop content inside the box and with a console.log view the content in the browser console:
File { name: "deam230mthumb.jpg", lastModified: 1194641808000, lastModifiedDate: Date 2007-11-09T20:56:48.000Z, size: 60313, type: "image/jpeg" }
I want to view the image inside a box and then upload on submit.
Here my code is use Jade template engine:
Jade (HTML)
form(action="" enctype="multipart/form-data")
div(class="all-100 miniatures")
div(class="all-100 drop ink-droppable align-center fallback" id="dropZone" ondrop="drop(event)" ondragover="allowDrop(event)")
Javascript
script.
var dropZone = document.getElementById('dropZone');
function allowDrop(e){
e.preventDefault();
}
function drop(e){
var file = e.dataTransfer.files[0];
e.preventDefault();
console.log(file);
//e.target.appendChild(file);
}
I added an array for content each file from the event, on the following code we need to add a controller for handle each file from the array with a register of each one on the database.
script.
var dropZone = document.getElementById('dropZone');
function allowDrop(e){
e.preventDefault();
}
var files = [];
function drop(e){
var file = e.dataTransfer.files[0];
files.push(file);
console.log(file)
e.preventDefault();
var reader = new FileReader();
reader.onload = function(event){
var miniatures = document.getElementById("miniatures");
var img = new Image();
img.src = event.target.result;
var miniature = document.createElement("div");
miniature.className = "all-20";
miniature.appendChild(img);
miniatures.appendChild(miniature);
}
var readerContent = reader.readAsDataURL(file);
var input = document.getElementById("upload");
input.files = readerContent;
console.log(files);
}
Ok, my Javascript looks this now:
At this point we can drag images from our desktop to browser and view
them, now, we need to upload that files.
script.
var dropZone = document.getElementById('dropZone');
function allowDrop(e){
e.preventDefault();
}
function drop(e){
var file = e.dataTransfer.files[0];
e.preventDefault();
console.log(file);
var reader = new FileReader();
reader.onload = function(event){
var miniatures = document.getElementById('miniatures');
var miniature = new Image();
miniature.src = event.target.result;
miniature.width = 100;
miniatures.appendChild(miniature);
}
reader.readAsDataURL(file);
}
myApp.directive('fileModel', ['$parse', function($parse) {
return {
restrict: 'A',
link: function($scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(e) {
$scope.$apply(function(e) {
modelSetter($scope, element[0].files[0]);
});
$scope.setimage();
});
}
The above code is my directive.
In the function $scope.setimage()
$scope.setimage = function() {
var file = $scope.myFile;
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e) {
$scope.ImageSrc = e.target.result;
}
}
Whenever i choose the file,
<img width= 250 height=350 ng-src="{{ImageSrc}}"/>
<input type=`enter code here`"file" file-model="myFile"/>
Immediately the preview is not appearing. When i choose the second time, the preview for the previously selected image file is appearing. Not sure what is wrong.
Instead of element.bind('change', ..., you can use $scope.$watch on myFile, like so:
$scope.$watch('$scope.myFile', function(e) {
$scope.$apply(function(e) {
modelSetter($scope, element[0].files[0]);
});
$scope.setimage();
});
Note that $scope.myFile needs to be defined for this to occur, so if it's not defined in your directive you'll need to add this to your controller instead.
I added $scope.$apply for the imagesrc assignment and the image updated immediately.
$scope.setimage = function() {
var file = $scope.myFile;
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e) {
$scope.$apply(function(){
$scope.ImageSrc = e.target.result;
}); }
}
I know that I should follow the DRY principle in coding. However, I am not that into javascript so I want to ask how to make the code below more readable and maintanable.
$('#frontfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = frontvImageIsLoaded;
});
$('#rearfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = rearvImageIsLoaded;
});
$('#rightfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = rightvImageIsLoaded;
});
$('#leftfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = leftvImageIsLoaded;
});
//called after an image file has been chosen
function frontvImageIsLoaded(e) {
$("#frontimagepreview").attr('src', e.target.result);
$("#frontpreview-msg").css('color', 'green');
};
function rearvImageIsLoaded(e) {
$("#rearimagepreview").attr('src', e.target.result);
$("#rearpreview-msg").css('color', 'green');
};
function rightvImageIsLoaded(e) {
$("#rightimagepreview").attr('src', e.target.result);
$("#rightpreview-msg").css('color', 'green');
};
function leftvImageIsLoaded(e) {
$("#leftimagepreview").attr('src', e.target.result);
$("#leftpreview-msg").css('color', 'green');
};
This is the code for Main.Mod.image_change()
var image_change = function handleFileImageChange(obj){
//holds the image preview object
var file = obj.files[0];
var imagefile = file.type;
var match= ["image/jpeg","image/png","image/jpg"];
if(!((imagefile==match[0]) || (imagefile==match[1]) || (imagefile==match[2]))){
alert("Incorrect image file. You still be able to upload this form but the system " +
"will be using the default image.");
$("#preview-msg").css('color', 'red');
return false;
}else{
var reader = new FileReader();
//reader.onload = imageIsLoaded;
reader.readAsDataURL(obj.files[0]);
return reader;
}
};
The code above, will handle file input change event then change img src base on the file input.
I know the code i wrote really sucks since I have to repeat my code several times. How can I implement it in a more efficient way?
Thanks.
use , to combine selectors:
$('#frontfile_v,#rearfile_v').change(function(){
// ...
})
The "change" event will be bound to every object matched by the selector. This way you don't need to duplicate the binding.
Merge the "image loaded" functions into one function by passing parameters:
var idsMap = {
leftfile_v : {preview : '#frontimagepreview', msg : '#frontpreview-msg'},
// etc...
};
$('#leftfile_v,#rearfile_v').change(function(){
var ids = idsMap[$(this).attr('id')];
reader = Main.Mod.image_change(this);
reader.onload = function(e) {
imageIsLoaded(e, ids.preview, ids.msg);
};
});
function imageIsLoaded(e, preview, msg) {
$(preview).attr('src', e.target.result);
$(msg).css('color', 'green');
};
Yet another variant. As say #Malki: use comma in selector
$('#frontfile_v, #rearfile_v,#rightfile_v,#leftfile_v').change(function(){
var id = this.id.replace(/file_v$/,'');
reader = Main.Mod.image_change(this);
if(reader){ //for case when `image_change` return not "false"
// use mode generic function
reader.onload = function(e){
$("#"+id+"imagepreview").attr('src', e.target.result);
$("#"+id+"preview-msg").css('color', 'green');
};
}
});
As for handleFileImageChange you need use Array.indexOf function
var image_change = function handleFileImageChange(obj){
//holds the image preview object
var file = obj.files[0];
var imagefile = file.type;
var match= ["image/jpeg","image/png","image/jpg"];
if(match.indexOf(imagefile) == -1){
alert("Incorrect image file. You still be able to upload this form but the system will be using the default image.");
$("#preview-msg").css('color', 'red');
return false;
}else{
var reader = new FileReader();
//reader.onload = imageIsLoaded;
reader.readAsDataURL(file); //you not need use "obj.files[0]" because you already save it in "var file"
return reader;
}
};
The value of image isn't updated in the UI, even though the scope variable is changed.
Main Controller :
$scope.TVuploadModal = function($files) {
$scope.TvTemp.file = $files[0];
$scope.TvTemp.fileName = $files[0].name
var fileReader = new FileReader();
fileReader.readAsDataURL($scope.TvTemp.file);
fileReader.onload = function(e) {
$timeout(function() { $scope.TvTemp.file.dataUrl = e.target.result; });
};
$scope.ResourceOpenBannerImageCrop('lg');
}
$scope.ResourceOpenBannerImageCrop = function(size) {
$modal.open({ templateUrl: 'BannerImageCrop.html', controller: 'resourceBannerImageCropCtrl', backdrop: 'static', size: size, scope: $scope,
resolve: {
TVImages: function () {
return $scope.TVImages;
}
}
}).result.then(function(images) {
console.log("Hello.....");
console.log($scope.TVImages);
/*$scope.TVImages = images;*/ });
};
resourceBannerImageCropCtrl :
app.controller('resourceBannerImageCropCtrl', function($scope,$rootScope,TVImages,$routeParams, $modalInstance, $location, $upload,ResourceAdditionStepsUpdateService,mediaUploadService) {
$scope.myCroppedImage = '';
$scope.TVImages1 = TVImages;
$scope.showSpinner = false;
$scope.imageCrop = function() {
$scope.showSpinner = true;
var requestMap = { imagedata:$scope.myCroppedImage, fileName:$scope.TvTemp.fileName, fileType:"Resource Images", userId: $rootScope.currentLoggedInUserId }
var saveResourceImages = mediaUploadService.saveImagesToUserBucket(requestMap, function(response) {
$scope.showSpinner = false;
if (response.isSuccess) {
var image = {}
image.uniqueKey = response.data.uniqueKey
image.fileUrl = response.data.url
image.fileType = "Resource Images"
image.description = $scope.description
image.type = "IMAGE"
image.s3UploadStatus = response.data.s3UploadStatus
ResourceAdditionStepsUpdateService.saveResourceImages({resourceId : $scope.resourceMetadata.resourceData.id , image : image},function(response){
console.log(response.data.mediaList);
$scope.showSpinner = false;
if(response.isSuccess){
$scope.TVImages1 = [];
$scope.TVImages1 = response.data.mediaList;
if (!$scope.$$phase) {
$scope.$apply();
}
}
});
$modalInstance.close(/*$scope.volcareTVImages*/);
}
})
};
$scope.cancel = function() { $modalInstance.dismiss('cancel'); };
});
HTML:
<div class="col-sm-4 mb20" ng-repeat="image in TVImages">
//content
</div>
I am passing the scope variable (i.e $scope.TVImages) in resolve as you can see in the code I am updating the $scope.TVImages1.
As per my understanding of two way data binding, if $scope.TVImages1 is updated, then $scope.TVImages should also update via the resolve.
I also tried using $scope.$apply, but that didn't work.
What am I doing wrong?
Qasim,
Some days ago, I was also facing this kind of issue while updating the value of $scope variable which is assigned as ng-repeat variable in the the view.
Could you please try to use following line instead of $scope.TVImages
$rootScope.TVImages that will update the view variable.
Please let me know if you still facing some problem.