I have an object "order" with a property that is an array of images urls.
I've tried to create a list of tags with his source to this urls but the problem is these urls are behind an api server and I'm unable to access directly from tag. I'm not sure why I'm receiving a FileNotFoundException and not a Forbidden, but it doesn't matter for this issue.
All my normal requests to this api server are done with the option "withCredentials: true", the api use cookies for authentication.
There aren't an api resource to download the image, the access is directly to url. For example if I open the url with my browser (without login in web app) I received a forbidden error, but if I login to my app in browser and paste the image url, the image load correctly.
I'm working with Nativescript angular.
Any idea how could show this list of images?
UPDATE:
Following this issue and understanding that src property of Image tag does not send cookies to server, I've created an API end point to received the images like a normal API call.
This is my angular service:
public async getPhoto(orderId: number, photoName: string) {
return await nsHttp.getImage(this.config.API_URL + `/api/tablet/photos/${orderId}/${photoName}`);
}
This is the code where I load all data:
async loadData(id: number, fromSketch: boolean = false) {
this.order = await this.orderService.getOrderById(id);
for (let index = 0; index < this.order.photoNames.length; index++) {
this.imgTemp = await this.orderService.getPhoto(this.order.orderId, this.order.photoNames[index].photoName);
this.imagesJPG.push(this.imgTemp);
}
console.log('IMAGES: ', this.imagesJPG);
}
And this is the presentation code:
<ScrollView orientation="vertical" [visibility]="selectedPageItemIndex === 2 ? 'visible' : 'collapse'">
<StackLayout>
<CardView margin="10" elevation="5" radius="1" *ngFor="let photo of imagePhotos; let i = index">
<Image [src]="imagesJPG[i]"></Image>
</CardView>
</StackLayout>
</ScrollView>
If I try to show only one image, for example imagesJPG[0] the image is displayed correctly, but in a ngFor loop no images, no cardview, and no errors appear in console.
I'm not sure if this is the best code to received an array of images and show them, if you have any suggestion I could be very grateful.
Regards
Related
I got a basic WebView in Xamarin.Forms like this:
<WebView AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All" x:Name="ChartWebView" Style="{StaticResource BackgroundStyle}">
<WebView.Source>
<HtmlWebViewSource Html="{Binding ChartHTML}" />
</WebView.Source>
</WebView>
I use the WebView to display a Chart.js diagram which works perfectly fine. On my page i got a button where the user can request data.
private async Task RequestData()
{
//Doing some stuff to get data ...
BuildChartHTML();
}
private void BuildChartHTML()
{
var html = GetChartJSConfigString();
Device.BeginInvokeOnMainThread(() =>
{
ChartWebView.Source = new HtmlWebViewSource
{
Html = html
};
});
}
However, on iOS only, everytime on exactly the 10th request/reload the WebView gets blank. It also stays blank after that. I need to re-navigate to this page to get it up and running again. I tried adjusting the height on WebView.Navigated as described in this thread, without success.
The problem doesn't accure on Android with the same code base.
Open to any workarounds if this is a framework bug.
PS: I obviously made sure that the html I'm loading is not broken. I loaded the same data 10 times and i compared the html loaded on the 10th time where the WebView broke. It was exactly the same HTML string.
Turned out to be a problem with iOS WKWebView and the use of HTML canvas (chart.js is renderered on a canvas).
After debugging into my WebView (stupid me not thinking about that possiblity before), i found out that the canvas memory exceeded the limit. With the help of a solution posted here i managed to avoid this problem.
Keep in mind this solution is a little bit hacky. Basically what I've done is, as pointed out in the link above, i "deleted" the canvas everytime i reload my chart. By "deleting" i mean setting the canvas to width and height to zero. Applied to my code the solution looks like this:
Inside my javascript that runs in the browser i added a function like this:
function deleteCanvas() {
//Get the main canvas where the chart is rendered to
var chart = document.getElementById('chart');
chart.height = 0;
chart.width = 0;
}
And then everytime i call my BuildChartHTML() function i call this method in my c# code like this:
Device.BeginInvokeOnMainThread(() =>
{
ChartWebView.Source = new HtmlWebViewSource
{
Html = html
};
ChartWebView.Eval("deleteCanvas()");
});
I'm building a web app with AngularJS that will allow users to upload their own images. Right now all of my data is text based, so I am storing the text based data in Firebase. As far as I know, Firebase can't store images. What I want to do is store the user generated images somewhere simple (I'm thinking Amazon S3 or even Dropbox) and then reference the images via unique URLs, which I would store as text in Firebase.
My questions:
Does this seem like a valid approach?
Any recommended services for hosting the images?
How to upload an image to the hosting service and get the image's unique URL?
Right now I am allowing users to upload images on the front end with the following code, just not sure what to do with the images once I have them. Would appreciate any help, I'm very new to this!
HTML
<output id="list"></output>
<input type="file" id="files" name="files[]" class="button" multiple />
Upload Pictures</i>
Angular Controller
$scope.getImages = function(){
$("input[type='file']").trigger('click');
}
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
console.log(f);
// Only process image files.
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML = ['<img class="thumb" src="', e.target.result,
'" title="', escape(theFile.name), '"/>'].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
You could use a service like Cloudinary to host images uploaded by your users. There are Angular directives that making using the service pretty easy. You will need a small server-side component to encrypt the upload parameters.
Look into Zapier integration with S3. The idea is that you setup a queue collection in firebase where you would create a new instance with the binary of the file data. Then zapier listens to for child_added on this queue collection and does it's magic (that you don't have to worry about) to upload your file to S3 bucket. After everything is finished, the instance in the queue is deleted... No server side needed with that, except there might be some fees...
Here is the link https://zapier.com/zapbook/amazon-s3/
Currently I am creating an application where I display an uploaded file from CollectionFS and display it using the CollectionFS url return. Locally the image loads and is displayed. However once I deploy the application to meteor.com the image url does not work. With the console indicating that the image path cannot be found.
CollectionFS returns this url for my image:
/cfs/contacts/75erhMtuwjn66fQH3_default1.png
Locally when I deploy the app I can see the image using in my .html:
img src="/cfs/contacts/75erhMtuwjn66fQH3_default1.png"
The specific code returned by CollectionFS is in the .html file and is being called client side:
{{cfsFileUrl "defaultHandler" fileId=fileId collection="Collection"}}
Locally I use this address as the source for the uploaded image in my html:
localhost:port/cfs/contacts/75erhMtuwjn66fQH3_default1.png
But when I attempt to view the image of the deployed app using the same procedure, it returns with an error of url not found:
http://host.meteor/cfs/contacts/75erhMtuwjn66fQH3_default1.png.com
A file is added on a click event client side .js:
'change .fileUploader': function (e) {
var files = e.target.files;
var fileName = files[0].name;
for (var i = 0, f; f = files[i]; i++) {
var k = ContactsFS.storeFile(f);
Session.set('fileID', k);
}}
Server side:
ContactsFS.fileHandlers({
default1: function(options) {
return {
blob: options.blob,
fileRecord: options.fileRecord // if no blob then save result in fileHandle (added createdAt)
};
}});
Then I can call the url in html with the given function from collectionFS documentation:
{{cfsFileUrl "default1" fileId=fileId collection="ContactsFS"}}
Once again the problem isn't generating the url. Both locally and once deployed the app displays a url. It is using the image url as the source for the image tag that is giving me the problem.
CollectionFS had a bug. I contacted the creator with the issue and it is now resolved in the collectionFS package. The report and closed issue can be found at:
https://github.com/raix/Meteor-CollectionFS/issues/85
I have an iframe application in vk.com. I can use their API everything looks fine but when I want to load profile images I get Security Sandbox Error. When I print the result and errors I get This: (I am using Greensock ImageLoader)
MYURL : 'MY Image URL on cs408919 subdomain of vk'
Loading CrossDomain on cs408919
ScriptAccessDenied : Error #2048
SecurityError : Error #2048
Error : Error #2048
ScriptAccessDenied : Error #2123 Security SandBox Violation, No Policy Files Granted Access
It seems to me crossdomain.xml issue but I couldn't find right one. Thanks...
In additional to fsbmain's answer I want say you have to add following code:
Security.allowDomain("*");
Yes, it's crossdomain issue, vk sub-domains for images doesn't provide crossdomain.xml for user avatars, but you still able to load (and add to display list as well) them. What you can't do is to access the loaded content (and set smooth bitmap flag for example, or draw the hole stage with vk images on it).
If you need the access the content you can use this "policy-hack", but it's hack, so it can be fixed in any FP update (I guess even this answer may bring closer this moment:) ):
The idea is to listen the ADDED event if image Loader:
protected var _prepareloaderBitmap:Bitmap;
_prepareloader.addEventListener(Event.ADDED, onPrepareLoader);
_prepareloader.contentLoaderInfo.addEventListener(Event.COMPLETE, onPrepareLoader);
And the listener:
protected function onPrepareLoader(event:Event):void
{
//event ADDED fired only for Bitmap (not for SWFs)
if(event.type == Event.ADDED)
{
_prepareloaderBitmap = event.target as Bitmap;
}
else if (event.type == Event.COMPLETE)
{
if(_prepareloaderBitmap)
{
trace("loaded image size:", _prepareloaderBitmap.width, "x", _prepareloaderBitmap.height);
}
}
}
Having the reference to the loaded Bitmap you can now add it instead of crossdomain issued loader.
With firebugs net tab open i stated zooming in and out of google map and i found its making requests for the png images.
Ok with this i understood that we can request the images using the Ajax. but wait ? i always used to request html, jsox, txt and xml. Image ........ its strange for me ? Can some one please elaborate on this ?
Also i would like to know if text is downloaded we add it to some DOM element and it show up. How images retried from the ajax can be accessed ?
Any help or pointer will be great help :)
GMaps doesn't make XMLHttpRequests to get the images. They instead use a normal <img /> element that is injected via javascript.
They then use the "onload" and "onerror" events to detect if the image was loaded correctly.
They retry a download of the image if it times out. This is achieved by setting a timer and once it expires re-setting the src property of the image.
var tile = document.createElement('img');
var url = 'http://sometilehost/X.Y.Z.png';
var downloadTimeout = 10000; // Retry in 10 seconds
// Tile downloaded successfully
tile.onload = function (e) {
window.clearTimeout(tile.downloadTimer);
alert('tile downloaded');
};
// The tile couldn't be downloaded. 404, 503 ...
tile.onerror = function (e) {
window.clearTimeout(tile.downloadTimer);
alert('tile not downloaded');
};
// This will fire if the tile doesn't download in time
tile.downloadTimer = window.setTimeout(function () {
tile.src = url; // Start the download again
}, downloadTimeout);
tile.src = url;