angular2 filereader mysteriously fails - html

I'm using the setup shown below to read image file in angular2. I'm using input element to show the window to choose file and then trigger the addThumbnail function when the file is chosen. The click on the input is being triggered by another button. I noticed that the trigger of addThumbnail function sometimes fails silently i.e. the function is not even triggered after choosing a file. This happens may be 1 out of 5 times I'm not sure if this could happen because of the size of the file. I tried to debug this by setting a breakpoint inside addThumbnail function but that is not even being triggered.
<div class="extra-image-container">
<input type="file" accept="image/*" (change)="addThumbnail($event)" style="display:none;" #fileInput2/>
<div class="thumbnail-button" (click)="fileInput2.click()">
<span><i class="material-icons">photo_camera</i></span><br>
<span>Extra Images</span>
</div>
</div>
This is the addThumbnail function and the file reader function I'm using.
addThumbnail(event) {
console.log('adding thumbnail');
var subscription = this.readImage(event.target).subscribe((result) => {
this.thumbnails.push(result.imageUrl);
this.editedThumbnails.push(result.imageUrl);
subscription.unsubscribe()
});
}
readImage(inputValue: any) : Observable<any> {
var file:File = inputValue.files[0];
var myReader:FileReader = new FileReader();
var observable = new Observable(observer => {
myReader.onloadend = (e) => {
observer.next({imageUrl: myReader.result});
console.log("image loaded");
// var image = new Image();
// image.addEventListener("load", () => {
// observer.next({
// imageWidth: image.width,
// imageHeight: image.height,
// imageSize: file.size/1000,
// imageUrl: myReader.result
// })
// console.log("image loaded");
// })
// image.src = myReader.result;
}
myReader.readAsDataURL(file);//triggers the callback
})
return observable
}

It turns out that if you read same file one after another, then the change is not triggered because the files are same. So, to fix this all I had to do was set the value of input element to empty string after a file is loaded.
#ViewChild('fileInput2') private thumbImageInput: ElementRef;
// and in the addThumbnail method:
addThumbnail(event) {
var subscription = this.readImage2(event.target).subscribe((result) => {
this.thumbnails.push(result.imageUrl);
this.editedThumbnails.push(result.imageUrl);
window.URL.revokeObjectURL(result.imageUrl);
this.thumbImageInput.nativeElement.value = '';
});
}

Related

Forge Viewer Extension for Toolbar: How to add a custom combox

I am trying to add a custom combobox to the toolbar in the forge viewer. Below is the code for it. I am able to successfully able to add buttons and they are functional. But combobox is not. It adds a combobox but it does show the fly out menu when I click on it. Not sure what I am doing wrong. help!
function BuildingToolbarExtension(viewer, options) {
Autodesk.Viewing.Extension.call(this, viewer, options);
}
BuildingToolbarExtension.prototype = Object.create(Autodesk.Viewing.Extension.prototype);
BuildingToolbarExtension.prototype.constructor = BuildingToolbarExtension;
BuildingToolbarExtension.prototype.load = function () {
// Set background environment to "Infinity Pool"
// and make sure the environment background texture is visible
this.viewer.setLightPreset(6);
this.viewer.setEnvMapBackground(true);
// Ensure the model is centered
//this.viewer.fitToView();
return true;
};
BuildingToolbarExtension.prototype.unload = function () {
// nothing yet
if (this.subToolbar) {
this.viewer.toolbar.removeControl(this.subToolbar);
this.subToolbar = null;
}
};
BuildingToolbarExtension.prototype.onToolbarCreated = function (toolbar) {
alert('TODO: customize Viewer toolbar');
var viewer = this.viewer;
// Button 1
var button1 = new Autodesk.Viewing.UI.Button('show-env-bg-button');
button1.onClick = function (e) {
viewer.setEnvMapBackground(true);
};
button1.addClass('show-env-bg-button');
button1.setToolTip('Show Environment');
// Button 2
var button2 = new Autodesk.Viewing.UI.Button('hide-env-bg-button');
button2.onClick = function (e) {
viewer.setEnvMapBackground(false);
};
button2.addClass('hide-env-bg-button');
button2.setToolTip('Hide Environment');
var comboButton = new Autodesk.Viewing.UI.ComboButton('buildings');
comboButton.setToolTip('buildings');
this.floors = new Autodesk.Viewing.UI.ControlGroup('my-custom-toolbar1');
this.floors.addControl(button1);
this.floors.addControl(button2);
comboButton.addControl(this.floors);
comboButton._isCollapsed = true;
comboButton.onClick = function (e) {
this.setCollapsed(false);
}
// SubToolbar
this.subToolbar = new Autodesk.Viewing.UI.ControlGroup('my-custom-toolbar');
this.subToolbar.addControl(button1);
this.subToolbar.addControl(button2);
this.subToolbar.addControl(comboButton);
toolbar.addControl(this.subToolbar);
};
Autodesk.Viewing.theExtensionManager.registerExtension('BuildingToolbarExtension', BuildingToolbarExtension);
The ControlGroup is unnecessary in your case, please refer the following to add buttons to ComboButton
var comboButton = new Autodesk.Viewing.UI.ComboButton('buildings');
comboButton.setToolTip('buildings');
// Button 1
var button1 = new Autodesk.Viewing.UI.Button('show-env-bg-button');
button1.onClick = function (e) {
viewer.setEnvMapBackground(true);
};
button1.addClass('show-env-bg-button');
button1.setToolTip('Show Environment');
comboButton.addControl(button1);
// Button 2
var button2 = new Autodesk.Viewing.UI.Button('hide-env-bg-button');
button2.onClick = function (e) {
viewer.setEnvMapBackground(false);
};
button2.addClass('hide-env-bg-button');
button2.setToolTip('Hide Environment');
comboButton.addControl(button2);
Here are snapshots:
Before opening
After opening

how to automatically open the camera

To capture the image from mobile using React js code, I am using the following code
<input type="file" accept="image/*" capture onChange={this.loadFile}/>
This input tag is dependent on the state variables in reacting. When the input tag gets rendered, firstly it will ask the user to click the "choose file "button and then will open the camera.
So, can we open the camera directly such that the "Choose File" button doesn't come and directly on changing the state values the camera gets open?
The loadFile handler function is :-
loadFile = (event: any) => {
var reader = new FileReader();
reader.onload = function() {
output: HTMLImageElement;
var output = document.getElementById("output");
output.src = reader.result;
};
reader.readAsDataURL(event.target.files[0]);
// console.log(event.target.files[0]);
this.setState({
activeCameraToggle: 0,
photo1: event.target.files[0]
});
};
Check this library:
https://github.com/react-community/react-native-image-picker
After adding it to your project do this:
// Launch Camera:
ImagePicker.launchCamera(options, (response) => {
// Same code as in above section!
});

Unable to access subfolder html file through <a> tag

I have a main folder with index.html file for my html app. I have written a code in index.html of main folder to access the file (index.html) present in the sub folder as follows,
SubFile
When i click on the above link, it is not navigating to the subfile and instead the link of main folder index.html file changes to mainfolder/index.html#!/subfolder/index.html
I even tried changing the name of subfolder file but no success. What could be the problem?
I also want to navigate back to the main folder index.html from subfolder as follow,
Mainfile
But it is also not working. How can I achieve this as well?
Edited:
The file my-app.js is creating the issue. The code of my-app.js is as follows,
// Initialize your app
var myApp = new Framework7({
animateNavBackIcon: true,
// Enable templates auto precompilation
precompileTemplates: true,
// Enabled pages rendering using Template7
swipeBackPage: false,
swipeBackPageThreshold: 1,
swipePanel: "left",
swipePanelCloseOpposite: true,
pushState: true,
pushStateRoot: undefined,
pushStateNoAnimation: false,
pushStateSeparator: '#!/',
template7Pages: true
});
// Export selectors engine
var $$ = Dom7;
// Add main View
var mainView = myApp.addView('.view-main', {
// Enable dynamic Navbar
dynamicNavbar: false
});
$$(document).on('pageInit', function (e) {
$(".swipebox").swipebox();
$("#ContactForm").validate({
submitHandler: function(form) {
ajaxContact(form);
return false;
}
});
$('a.backbutton').click(function(){
parent.history.back();
return false;
});
$(".posts li").hide();
size_li = $(".posts li").size();
x=4;
$('.posts li:lt('+x+')').show();
$('#loadMore').click(function () {
x= (x+1 <= size_li) ? x+1 : size_li;
$('.posts li:lt('+x+')').show();
if(x == size_li){
$('#loadMore').hide();
$('#showLess').show();
}
});
$("a.switcher").bind("click", function(e){
e.preventDefault();
var theid = $(this).attr("id");
var theproducts = $("ul#photoslist");
var classNames = $(this).attr('class').split(' ');
if($(this).hasClass("active")) {
// if currently clicked button has the active class
// then we do nothing!
return false;
} else {
// otherwise we are clicking on the inactive button
// and in the process of switching views!
if(theid == "view13") {
$(this).addClass("active");
$("#view11").removeClass("active");
$("#view11").children("img").attr("src","images/switch_11.png");
$("#view12").removeClass("active");
$("#view12").children("img").attr("src","images/switch_12.png");
var theimg = $(this).children("img");
theimg.attr("src","images/switch_13_active.png");
// remove the list class and change to grid
theproducts.removeClass("photo_gallery_11");
theproducts.removeClass("photo_gallery_12");
theproducts.addClass("photo_gallery_13");
}
else if(theid == "view12") {
$(this).addClass("active");
$("#view11").removeClass("active");
$("#view11").children("img").attr("src","images/switch_11.png");
$("#view13").removeClass("active");
$("#view13").children("img").attr("src","images/switch_13.png");
var theimg = $(this).children("img");
theimg.attr("src","images/switch_12_active.png");
// remove the list class and change to grid
theproducts.removeClass("photo_gallery_11");
theproducts.removeClass("photo_gallery_13");
theproducts.addClass("photo_gallery_12");
}
else if(theid == "view11") {
$("#view12").removeClass("active");
$("#view12").children("img").attr("src","images/switch_12.png");
$("#view13").removeClass("active");
$("#view13").children("img").attr("src","images/switch_13.png");
var theimg = $(this).children("img");
theimg.attr("src","images/switch_11_active.png");
// remove the list class and change to grid
theproducts.removeClass("photo_gallery_12");
theproducts.removeClass("photo_gallery_13");
theproducts.addClass("photo_gallery_11");
}
}
});
document.addEventListener('touchmove', function(event) {
if(event.target.parentNode.className.indexOf('navbarpages') != -1 || event.target.className.indexOf('navbarpages') != -1 ) {
event.preventDefault(); }
}, false);
// Add ScrollFix
var scrollingContent = document.getElementById("pages_maincontent");
new ScrollFix(scrollingContent);
var ScrollFix = function(elem) {
// Variables to track inputs
var startY = startTopScroll = deltaY = undefined,
elem = elem || elem.querySelector(elem);
// If there is no element, then do nothing
if(!elem)
return;
// Handle the start of interactions
elem.addEventListener('touchstart', function(event){
startY = event.touches[0].pageY;
startTopScroll = elem.scrollTop;
if(startTopScroll <= 0)
elem.scrollTop = 1;
if(startTopScroll + elem.offsetHeight >= elem.scrollHeight)
elem.scrollTop = elem.scrollHeight - elem.offsetHeight - 1;
}, false);
};
})
What shall i remove from it to solve my problem?
#!/subfolder/index.html
This make me feel that you are using a single page application framework/library, like Angular or something related. So maybe your problem is not in the html but in your javascript code.
Please remove all javascript and check it will work fine then revert all js one by one and test you will find the conflict javascript resolve that conflict. it will work fine.

chrome.storage.sync does not store the data

I am trying to store the data a user enters inside a textarea in a popup.html. Using jQuery on window unload the data should be synced and on window ready the data should be restored. However, when opening popup.html the content of the textarea is undefined. This is the jQuery code which I am loading in popup.html:
$(window).unload (
function save() {
var textarea = document.querySelector("#contacts").value;
// Old method of storing data locally
//localStorage["contacts"] = textarea.value;
// Save data using the Chrome extension storage API.
chrome.storage.sync.set({contacts: textarea}, function() {
console.log("Contacts saved");
});
});
$(window).ready(
function restore() {
var textarea = document.querySelector("#contacts");
// Old method of retrieving data locally
// var content = localStorage["contacts"];
chrome.storage.sync.get('contacts', function(r) {
console.log("Contacts retrieved");
var content = r["contacts"];
textarea.value = content;
});
});
From popup.js you can invoke a method in background.js file to save the data:
popup.js:
addEventListener("unload", function(){
var background = chrome.extension.getBackgroundPage();
background.mySavefunction(data);
}
background.js:
function mySaveFunction(data){
chrome.storage.sync.set(data, function(){
console.log("Data saved.");
});
}
I found a solution. Instead of using $(window).unload() I now use a submit button which needs to be clicked before closing popup.html:
$("#save-button").click(function() {
var textarea = document.querySelector("#contacts").value;
var save = {};
save["contacts"] = textarea;
// Save data using the Chrome extension storage API.
chrome.storage.sync.set(save, function() {
console.log("Contacts saved");
});
$("#confirm").text("Contacts saved.").show().fadeOut(5000);
});

HTML FileReader

function fileSelected() {
// get selected file element
var files = document.getElementById('files[]').files;
for (var i = 0; i < files.length; i++) //for multiple files
{
(function (file) {
var fileObj = {
Size: bytesToSize(file.size),
Type: file.type,
Name: file.name,
Data: null
};
var reader = new window.FileReader();
reader.onload = function (e) {
fileObj.Data = e.target.result;
};
// read selected file as DataURL
reader.readAsDataURL(file);
//Create Item
CreateFileUploadItem(fileObj);
})(files[i]);
}
}
function CreateFileUploadItem (item) {
console.log(item);
$('<li>', {
"class": item.Type,
"data-file": item.Data,
"html": item.Name + ' ' + item.Size
}).appendTo($('#filesForUpload'));
}
So when console.log(item) gets run in the CreateFileUploadItem function it shows the item.Data. YET it won't add it to the data-file of the LI. Why is that?
The call to readAsDataURL is asynchronous. Thus, the function call is likely returning prior to the onload function being called. So, the value of fileObj.Data is still null when you are attempting to use it in CreateFileUploadItem.
To fix it, you should move the call to CreateFileUploadItem into your onload function. As for the console logging the proper value, you can't rely on that being synchronous either. I think using a breakpoint during debugging at that line instead will likely show the true null value.