Upload csv file to S3 bucket from static webpage - javascript

I'm trying to create an upload webpage to put csv files in a S3 bucket.
I followed the tutorial from their website. https://aws.amazon.com/blogs/compute/uploading-to-amazon-s3-directly-from-a-web-or-mobile-application/
I modified the method to accept parameter filename. Everything works fine but can't find the way to upload file from html to S3.
I'm usual a backend pythonist and google to change this webpage/js, but I didn't manage to solve it.
I tried to change from reader.readAsDataURL(file) to reader.readAsText(file, 'UTF-8'), also data:image/jpg to data:text/csv or text/plain but on line that requires "includes" returns "length: false"
console.log('length: ', e.target.result.includes('data:image/jpeg'))
Down you can find my new code, if you can redirect me to some clues of how can I send csv file and also "?filename=original filename" in API, I'll really love you :).
<!DOCTYPE html>
<html>
<head>
<title>Upload file to S3</title>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios#0.2.1/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<h1>S3 Uploader Test</h1>
<div v-if="!file">
<h2>Select a file</h2>
<input type="file" #change="onFileChange">
</div>
<div v-else>
<img :src="file" />
<button v-if="!uploadURL" #click="removeFile">Remove file</button>
<button v-if="!uploadURL" #click="uploadFile">Upload file</button>
</div>
<h2 v-if="uploadURL">Success! File uploaded to bucket.</h2>
</div>
<script>
const MAX_FILE_SIZE = 1000000
/* ENTER YOUR ENDPOINT HERE */
const API_ENDPOINT = 'https://<smth>.execute-api.eu-central-1.amazonaws.com/uploads'
// e.g. https://ab1234ab123.execute-api.us-east-1.amazonaws.com/uploads
new Vue({
el: "#app",
data: {
file: '',
uploadURL: ''
},
methods: {
onFileChange (e) {
let files = e.target.files || e.dataTransfer.files
if (!files.length) return
this.createFile(files[0])
},
createFile (file) {
// var image = new Image()
let reader = new FileReader()
reader.readAsText(file, 'UTF-8');
reader.onload = (e) => {
//console.log(e.target.result)
console.log('length: ', e.target.result.includes('data:/csv'))
if (!e.target.result.includes('data:text/csv')) {
return alert('Wrong file type', e.target.result)
}
if (e.target.result.length > MAX_FILE_SIZE) {
return alert('File is loo large.')
}
this.file = e.target.result
}
// reader.readAsDataURL(file)
},
removeFile: function (e) {
console.log('Remove clicked')
this.file = ''
},
uploadFile: async function (e) {
console.log('Upload clicked')
// Get the presigned URL
const response = await axios({
method: 'GET',
url: API_ENDPOINT+'?filename='+'last.csv'
})
console.log('Response: ', response)
console.log('Uploading: ', this.file)
let binary = atob(this.file.split(',')[1])
let array = []
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i))
}
let blobData = new Blob([new Uint8Array(array)], {type: 'text/csv'})
console.log('Uploading to: ', response.uploadURL)
const result = await fetch(response.uploadURL, {
method: 'PUT',
body: blobData
})
console.log('Result: ', result)
// Final URL for the user doesn't need the query string params
this.uploadURL = response.uploadURL.split('?')[0]
}
}
})
</script>
<style type="text/css">
body {
background: #20262E;
padding: 20px;
font-family: sans-serif;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
text-align: center;
}
#logo {
width: 100px;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
h1, h2 {
font-weight: normal;
margin-bottom: 15px;
}
a {
color: #42b983;
}
img {
width: 30%;
margin: auto;
display: block;
margin-bottom: 10px;
}
</style>
</body>
</html>

As you are creating a static web site that uses script tags, consider using the AWS SDK for JavaScript to place objects into an Amazon S3 bucket. Uploading objects is covered in the AWS Developer Guide for JavaScript SDK Version 3.
Uploading photos to Amazon S3 from a browser
(Of course for your use case, replace photo files with a CSV file).

Thanks #smac2020 for direction, still pretty useful I didn't have the chance to study it more.
After few hours of vue.js learning, made this working code.
<!DOCTYPE html>
<html>
<head>
<title>Upload file to S3</title>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios#0.2.1/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<h1>S3 Uploader Test</h1>
<div v-if="!file">
<h2>Select a file</h2>
<input type="file" #change="onFileChange">
</div>
<div v-else>
<div>File {{ name }} loaded </div>
<button v-if="!uploadURL" #click="removeFile">Remove file</button>
<button v-if="!uploadURL" #click="uploadFile">Upload file</button>
</div>
<h2 v-if="uploadURL">Success! File uploaded to bucket.</h2>
</div>
<script>
const MAX_FILE_SIZE = 1000000
/* ENTER YOUR ENDPOINT HERE */
const API_ENDPOINT = 'https://<smth>.execute-api.eu-central-1.amazonaws.com/uploads'
// e.g. https://ab1234ab123.execute-api.us-east-1.amazonaws.com/uploads
new Vue({
el: "#app",
data: {
file: '',
uploadURL: '',
name: ''
},
methods: {
onFileChange (e) {
let files = e.target.files || e.dataTransfer.files
if (!files.length) return
this.createFile(files[0])
},
createFile (file) {
let reader = new FileReader()
this.name = file.name
console.log(this.name)
reader.readAsText(file, 'UTF-8');
reader.onload = (e) => {
if (e.target.result.length > MAX_FILE_SIZE) {
return alert('File is loo large.')
}
this.file = e.target.result
}
},
removeFile: function (e) {
console.log('Remove clicked')
this.file = ''
},
uploadFile: async function (e) {
console.log('Upload clicked', this.name)
// Get the presigned URL
const response = await axios({
method: 'GET',
url: API_ENDPOINT+'?filename='+this.name
})
console.log('Response: ', response)
let blobData = new Blob([this.file], {type: 'text/csv'})
console.log('Uploading to: ', response.uploadURL)
const result = await fetch(response.uploadURL, {
method: 'PUT',
body: blobData
})
console.log('Result: ', result)
// Final URL for the user doesn't need the query string params
this.uploadURL = response.uploadURL.split('?')[0]
}
}
})
</script>
<style type="text/css">
body {
background: #20262E;
padding: 20px;
font-family: sans-serif;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
text-align: center;
}
#logo {
width: 100px;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
h1, h2 {
font-weight: normal;
margin-bottom: 15px;
}
a {
color: #42b983;
}
img {
width: 30%;
margin: auto;
display: block;
margin-bottom: 10px;
}
</style>
</body>
</html>

Related

Nativescript playground vue.js show error message "TypeError: undefined is not an object (evaluating 'res.list.splice)"

Link(My weather apps)
export const WEATHER_URL = "https://api.openweathermap.org/data/2.5/";
export const WEATHER_APIKEY = "2b27b121d7923afe1e02876057a88c10"; // from OpenWeatherMap
export const CURRENT_WEATHER_PATH = "weather/";
export const WEATHER_FORECAST_PATH = "forecast/daily/";
export const WEATHER_ICONS = {
day: {
clear: 0xf00d,
clouds: 0xf002,
drizzle: 0xf009,
rain: 0xf008,
thunderstorm: 0xf010,
snow: 0xf00a,
mist: 0xf0b6
},
night: {
clear: 0xf02e,
clouds: 0xf086,
drizzle: 0xf029,
rain: 0xf028,
thunderstorm: 0xf02d,
snow: 0xf02a,
mist: 0xf04a
},
neutral: {
temperature: 0xf055,
wind: 0xf050,
cloud: 0xf041,
pressure: 0xf079,
humidity: 0xf07a,
rain: 0xf019,
sunrise: 0xf051,
sunset: 0xf052
}
};
export const WIND_DIRECTIONS = [
"North",
"North-northeast",
"Northeast",
"East-northeast",
"East",
"East-southeast",
"Southeast",
"South-southeast",
"South",
"South-southwest",
"Southwest",
"West-southwest",
"West",
"West-northwest",
"Northwest",
"North-northwest"
];
I am a beginner in nativescript(vue.js), I am trying to design mobile phone apps that provide weather information to users. When I test the apps, it shows me an error message "TypeError: undefined is not an object (evaluating 'res.list.splice')" Could someone help me solve this error? Here is my code:
<template>
<Page class="page" #loaded="getForecast" :class="background_class">
<ActionBar title="15-hours Forecast" class="action-bar">
<NavigationButton android.systemIcon="ic_menu_back"
#tap="goToMainPage" />
</ActionBar>
<StackLayout orientation="vertical" width="100%" height="100%">
<ListView for="weather in forecastWeather" height="90%"
:class="background_class">
<v-template>
<GridLayout class="item" columns="*,*" rows="auto">
<StackLayout class="day-weather" row="0" col="0">
<Label :text="weather.day" class="date" />
<Label :text="weather.icon" class="icon" />
<Label :text="weather.description"
textWrap="true" />
</StackLayout>
<StackLayout class="details" row="0" col="1">
<GridLayout columns="auto,auto" rows="auto"
row="0" col="0">
<Label :text="weather.temperature.temp_max"
class="temp day-temp" row="0" col="0" />
<Label :text="weather.temperature.temp_min"
class="temp night-temp" row="0" col="1" />
</GridLayout>
<Label :text="weather.wind" />
<Label :text="weather.clouds" />
<Label :text="weather.pressure" />
</StackLayout>
</GridLayout>
</v-template>
</ListView>
<Label :text="msg" textWrap="true" />
</StackLayout>
</Page>
</template>
<script>
import Forecast from "./ForecastWeather";
const appSettings = require("tns-core-modules/application-settings");
const requestor = require("./common/Requestor");
const moment = require("~/moment");
const constants = require("./common/Constants");
const utilities = require("./common/Utilities");
export default {
methods: {
goToMainPage() {
this.$navigateBack();
},
getForecast() {
this.background_class = utilities.getTimeOfDay();
var url =
constants.WEATHER_URL +
constants.WEATHER_FORECAST_PATH +
"?lat=" +
this.currentGeoLocation.latitude +
"&lon=" +
this.currentGeoLocation.longitude +
"&apikey=" +
constants.WEATHER_APIKEY;
requestor
.get(url)
.then(res => {
var forecast = [];
this.msg = "Retriving data...";
var list = res.list.splice(0, 5);
list.forEach(item => {
this.forecastWeather.push({
day: moment.unix(item.dt)
.format("HH:00"),
icon: constants
.WEATHER_ICONS["day"][
item.weather[0]
.main
.toLowerCase()
],
temperature: {
temp_max: utilities
.convertKelvinToCelsius(
item.main
.temp_max)
.toFixed(2),
temp_min: utilities
.convertKelvinToCelsius(
item.main
.temp_min)
.toFixed(2)
},
wind: item.wind.speed +
" m/s",
clouds: item.clouds.all +
" %",
pressure: item.main
.pressure + " hpa",
description: item.weather[
0].description
});
});
this.forecastWeather = this.forecastWeather
.splice(0, 5);
this.msg = "Ready";
})
.catch(error => {
this.msg = error + " (Error: 201)";
});
}
},
data() {
return {
currentGeoLocation: {
latitude: null,
longitude: null
},
msg: "",
forecastWeather: [],
background_class: ".day"
};
},
created() {
this.currentGeoLocation.latitude = appSettings.getNumber("clat");
this.currentGeoLocation.longitude = appSettings.getNumber("clon");
this.temp =
this.currentGeoLocation.latitude +
", " +
this.currentGeoLocation.longitude;
this.getForecast();
}
};
</script>
<style>
Page {
font-size: 15px;
}
.item {
padding: 20px 10px;
}
.day-weather {
text-align: center;
}
.details {
horizontal-align:
left;
}
.date {
font-size: 20px;
}
.icon {
font-size: 30px;
}
.temp {
padding: 3px;
text-align:
center;
font-size: 15px;
}
.day-temp {
background-color: #d0c110;
}
.night-temp {
background-color: #505050;
color: #FFF;
}
</style>
Unless you changed the API key the response when requesting the forecast is:
{
"cod": 401,
"message": "Invalid API key. Please see http://openweathermap.org/faq#error401 for more info."
}
Solution: You might have to enable your API key for each endpoint separately, because it does work for when requesting the current weather.
IMPORTANT: With the posted code block/linked code you exposed your API key. Make sure you reset/regenerate it and the current API key does no longer work.
The important thing to note is that fetch() within you Requestor does not check if the response is ok.
export function get(url) {
return fetch(
url
).then(function (response) {
return response.json();
}).then(function (json) {
return json;
});
}
The fetch() documentation says:
The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from completing.
This means like Requestor is currently written you should check the data.cod for a success response (200). Alternatively you could rewrite your Requestor to throw on a not-ok response.
// Return parsed JSON if response is ok. When the response is not ok
// reject with the response as error object.
export function get(url) {
return fetch(url).then((response) => {
if (!response.ok) throw response;
return response.json();
});
}

Bot donot send welcome msg on its own in Direct line

I have created a bot locally using bot framework v4 c#. It has a welcome card that automatically pops up as soon I connect my local url with emulator, but recently I deployed my bot on azure and integrated it using direct line channel in my website. Now whenever I click, it opens the bot but the welcome card does not come on its own ,it appears when I write something from my chatbot. I just want the welcome card to appaer automatically as it appears in the emulator. Guys can you help me out please? Below is the code of direct line which I am integrating in my website.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<!-- Paste line 7 to 27 after the title tag in _Layout.cshtml -->
<link href="https://cdn.botframework.com/botframework-webchat/latest/botchat.css" rel="stylesheet"
/>
<script src="https://cdn.botframework.com/botframework-webchat/latest/botchat.js"></script>
<style>
#mychat {
margin: 10px;
position: fixed;
bottom: 30px;
left: 10px;
z-index: 1000000;
}
.botIcon {
float: left !important;
border-radius: 50%;
}
.userIcon {
float: right !important;
border-radius: 50%;
}
</style>
</head>
< body>
<!-- Paste line from 31 to 33 before the </body> tag at the end of code -->
<div id="container">
<img id="mychat" src=""/>
</div>
</body>
<!-- Paste line 38 to 88 after the </html> tag -->
<script>
(function () {
var div = document.createElement("div");
var user = {
id: "",
name: ''
};
var bot = {
id: '',
name: 'SaathiBot'
};
const botConnection = new BotChat.DirectLine({
secret: '',
webSocket: false
})
document.getElementsByTagName('body')[0].appendChild(div);
div.outerHTML = "<div id='botDiv' style='width: 400px; height: 0px; margin:10px; position:
fixed; bottom: 0; left:0; z-index: 1000;><div id='botTitleBar' style='height: 40px; width: 400px;
position:fixed; cursor: pointer;'>";
BotChat.App({
botConnection: botConnection,
user: user,
bot: bot
}, document.getElementById("botDiv"));
document.getElementsByClassName("wc-header")[0].setAttribute("id", "chatbotheader");
document.querySelector('body').addEventListener('click', function (e) {
e.target.matches = e.target.matches || e.target.msMatchesSelector;
if (e.target.matches('#chatbotheader')) {
var botDiv = document.querySelector('#botDiv');
botDiv.style.height = "0px";
document.getElementById("mychat").style.display = "block";
};
});
document.getElementById("mychat").addEventListener("click", function (e) {
document.getElementById("botDiv").style.height = '500px';
e.target.style.display = "none";
})
}());
</script>
Also here is my welcome card code in c#
namespace Microsoft.BotBuilderSamples
{
public class WelcomeUser : SaathiDialogBot<MainDialog>
{
protected readonly string[] _cards =
{
Path.Combine(".", "Resources", "WelcomeCard.json"),
};
public WelcomeUser(ConversationState conversationState, UserState userState, MainDialog dialog, ILogger<SaathiDialogBot<MainDialog>> logger)
: base(conversationState, userState, dialog, logger)
{
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
await SendWelcomeMessageAsync(turnContext, cancellationToken);
Random r = new Random();
var cardAttachment = CreateAdaptiveCardAttachment(_cards[r.Next(_cards.Length)]);
await turnContext.SendActivityAsync(MessageFactory.Attachment(cardAttachment), cancellationToken);
}
private static async Task SendWelcomeMessageAsync(ITurnContext turnContext, CancellationToken cancellationToken)
{
foreach (var member in turnContext.Activity.MembersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
if (DateTime.Now.Hour < 12)
{
await turnContext.SendActivityAsync(
$"Hi,Good Morning {member.Name}",
cancellationToken: cancellationToken);
}
else if (DateTime.Now.Hour < 17)
{
await turnContext.SendActivityAsync(
$"Hi,Good Afternoon {member.Name}",
cancellationToken: cancellationToken);
}
else
{
await turnContext.SendActivityAsync(
$"Hi,Good Evening {member.Name}",
cancellationToken: cancellationToken);
}
}
}
}
private static Attachment CreateAdaptiveCardAttachment(string filePath)
{
var adaptiveCardJson = File.ReadAllText(filePath);
var adaptiveCardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCardJson),
};
return adaptiveCardAttachment;
}
}
}
Here the saathiDialog code which inherited in welcome card. These are the two files inside my bot folder
namespace Microsoft.BotBuilderSamples
{
public class SaathiDialogBot<T> : ActivityHandler where T : Dialog
{
protected readonly BotState ConversationState;
protected readonly Dialog Dialog;
protected readonly ILogger Logger;
protected readonly BotState UserState;
private DialogSet Dialogs { get; set; }
public SaathiDialogBot(ConversationState conversationState, UserState userState, T dialog, ILogger<SaathiDialogBot<T>> logger)
{
ConversationState = conversationState;
UserState = userState;
Dialog = dialog;
Logger = logger;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
var activity = turnContext.Activity;
if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
{
activity.Text = JsonConvert.SerializeObject(activity.Value);
}
if (turnContext.Activity.Text == "Yes")
{
await turnContext.SendActivityAsync($"Good bye. I will be here if you need me. ", cancellationToken: cancellationToken);
await turnContext.SendActivityAsync($"Say Hi to wake me up.", cancellationToken: cancellationToken);
}
else
{
await base.OnTurnAsync(turnContext, cancellationToken);
}
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
Logger.LogInformation("Running dialog with Message Activity.");
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
}
}
If you are using WebChat or directline, the bot’s ConversationUpdate is sent when the conversation is created and the user sides’ ConversationUpdate is sent when they first send a message. When ConversationUpdate is initially sent, there isn’t enough information in the message to construct the dialog stack. The reason that this appears to work in the emulator, is that the emulator simulates a sort of pseudo DirectLine, but both conversationUpdates are resolved at the same time in the emulator, and this is not the case for how the actual service performs.
A workaround would be to send a back channel welcome event to the bot when the DirectLine connection is established and send a welcome message from the onEventAsync handler instead of onMembersAdded.
Embedded HTML for Web Chat
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<style>
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div style="display: flex">
<div style="position: relative; height: 500px; width: 500px"><div id="bot" ></div></div>
</div>
<script>
(async function() {
const res = await fetch('/directline/token', { method: 'POST' });
const { token } = await res.json();
var userinfo = {
id: 'user-id',
name: 'user name',
locale: 'es'
};
var botConnection = new window.BotChat.DirectLine({ token });
botConnection.connectionStatus$
.subscribe(connectionStatus => {
switch(connectionStatus) {
case window.BotChat.ConnectionStatus.Online:
botConnection.postActivity({
from: { id: 'myUserId', name: 'myUserName' },
type: 'event',
name: 'webchat/join',
value: { locale: 'en-US' }
}).subscribe(
id => console.log("Posted welcome event, assigned ID ", id),
error => console.log("Error posting activity", error)
);
break;
}
});
BotChat.App({
botConnection: botConnection,
user: userinfo,
bot: { id: 'botid' },
resize: 'detect'
}, document.getElementById("bot"));
})().catch(err => console.log(err));
</script>
</body>
</html>
Bot Code in C#
protected override async Task OnEventActivityAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.Name == "webchat/join") {
await turnContext.SendActivityAsync("Welcome Message!");
}
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.ChannelId != "webchat" && turnContext.Activity.ChannelId != "directline") {
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync($"Hi there - {member.Name}. {WelcomeMessage}", cancellationToken: cancellationToken);
await turnContext.SendActivityAsync(InfoMessage, cancellationToken: cancellationToken);
await turnContext.SendActivityAsync(PatternMessage, cancellationToken: cancellationToken);
}
}
}
}
Hope this helps.
Send a custom event activity.
For more information, please check this link

How to return string from a Promise

Im working on a website with vue where i have to get images with axios from a server and put them as background images of divs. The case is that i have the urls but not all of them are correct. So im trying to make a function that makes an http request and returns me the url if that request is successful.
I thought of something like this:
Template:
<div class="element" :style="bgImg(url)"/>
Script:
methods: {
bgImg(url) {
axios.get(url)
.then(response => {
return `background-image: url(${response.config.url})`;
})
.cath(e) {
throw new Error(e);
}
}
}
I was expecting to get the url returned from that function, but nothing happens.
You could use a custom vue directive for that job:
Vue.directive('validate-bgimg', function (el, binding) {
el.style.backgroundImage = null // reset
var url = binding.value
if (!url) {
return
}
axios.get(`https://cors-anywhere.herokuapp.com/${url}`) // get around CORS limitations. Idealy you should call your own api to validate image urls
.then(response => {
if (response.status != 200) {
console.warn("Invalide image url", url, response)
} else {
el.style.backgroundImage = `url(${url})`
}
})
.catch(e => {
console.error("Could not validate image", url, e)
})
})
new Vue({
el: "#app",
data: {
imgUrl: undefined
}
})
#app {
background: lightgray;
border-radius: 4px;
padding: 20px;
margin: 20px;
transition: all 0.2s;
}
.element {
margin: 8px 0;
width: 200px;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<b>test case:</b>
<button #click="imgUrl='https://dummyimage.com/200x200/000/fff.gif&text=test+1'">1</button>
<button #click="imgUrl='https://dummyimage.com/200x200/000/fff.gif&text=test+2'">2</button>
<button #click="imgUrl='https://dummyimage.com/200x200/000/fff.gif&text=test+3'">3</button>
<button #click="imgUrl='https://httpbin.org/status/404'">HTTP 404</button>
<button #click="imgUrl='https://httpbin.org/status/503'">HTTP 503</button>
<button #click="imgUrl='https://invalid.tld'">cannot resolve domain name</button>
<div class="element" v-validate-bgimg="imgUrl"/>
</div>
You should use setAttribute method.
//add id to the element
<div id="element" class="element" />
var url = url(${response.config.url});
// select the element using id and set image
document.getElementById("element").setAttribute("style", "background-image:"+ url);
Rather than returning from a then() callback (which will pass the result of the block to the next then()), you can store the data that you are seeking from the response object for use outside of the promise.
Use a computed or temp value, that will make it easier.
In this solution, you would set a placeholder image to show while loading (or leave empty).
Then use a mounted() hook to load data, and then assign to the style
Template:
<div class="element" :style="imgStyle"/>
Script:
data:{
return () => {
imgStyle: {
'background-image': 'url(my-placeholder.png)' // or not included at all
}
}
},
mounted() {
axios.get(url)
.then(response => {
this.$set(this.imgStyle, 'background-image', `url(${response.config.url})`);
})
.cath(e) {
throw new Error(e);
}
}
As a side note, try to stay away from functions in templates for displaying values that can be done using a computed.

change data key name came from JSON dynamically AngularJS

I have a multi-select that I made with angular-ui.
I want to add an input that user can change the JSON key names so for example if the API that user add doesn't have "name" instead has "firstName" as the "key name" the app changes that and can work fine.
how can I get this result?
appreciate any help.
my code is here
what I really want is this: I should add this multi-select as a widget to a software named bonita studio and it should have an option that user can choose any API that want to use and should have an input field that the user will choose which one of the API's key identifier to iterate. for example if instead of name the user wants to iterate over the email s/he should be able to do.
I hope this explanation is enough
"use strict";
var app = angular.module("myApp", ['ui.select', 'ngSanitize']);
app.controller("myCtrl", function($scope, $http) {
$scope.headers = "";
var counter = 0;
var chunks = 5;
$scope.datas = [];
$scope.getData = function getData() {
return $http({
method: "GET",
url: "data.json"
})
.then(function onSuccess(response) {
for (let i = 0; i < response.data.length; i++) {
$scope.datas.push(response.data[i]);
}
//counter += chunks;
})
.catch(function onError(response) {
console.log(response.status);
});
}
/*$scope.loadMore = function () {
$http({
method: "GET",
url: "data.json"
})
.then(function loadMoreSuccess(response) {
for (let i = counter; i < (counter + chunks); i++) {
$scope.datas.push(response.data[i]);
}
counter += chunks;
})
.catch(function onError(response) {
console.log(response.status);
});
};*/
$scope.selected = {
value: $scope.datas[0]
};
});
#widgetContainer {
width: 100%;
}
ul li {
list-style: none;
text-align: center;
}
ul {
height: 120px;
overflow-y: auto;
}
#loadMore {
text-align: center;
color: #aaa;
background: #ddd;
cursor: pointer;
}
#category {
text-align: center;
background: #ddd;
}
#listContainer {
width: 20%;
}
span {
cursor: pointer;
}
h4 {
background: #ddd;
color: #aaa;
}
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="script/lib/angular/angular.js"></script>
<script src="https://code.angularjs.org/1.6.10/angular-sanitize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.min.css">
<link rel="stylesheet" href="stylesheet/style.css">
</head>
<body ng-controller="myCtrl">
<div class="container">
<input type="text" ng-model="headers">
<ui-select multiple spinner-enabled="true" close-on-select="false" ng-model="selected.value">
<ui-select-no-choice>
couldn't find anything...
</ui-select-no-choice>
<ui-select-match placeholder="Select country...">
<span>{{$item.name}}</span>
</ui-select-match>
<ui-select-choices group-by="'category'" repeat="data in (datas | filter: $select.search) track by $index" refresh="getData($select.search)" refresh-delay="0">
<span>{{data.name}}</span>
</ui-select-choices>
</ui-select>
</div>
<script src="script/script.js"></script>
</body>
</html>
// Supose you have an object with desired change relations:
var relations = { firstName: "name", oldKey: "newKey" };
// Also, you have your dataArray:
var dataArray = [
{ firstName: "foo", oldKey: 1 },
{ firstName: "bar", oldKey: 2 }
];
// Here follows how you can switch keys:
Object.entries(relations).map(([oldKey, newKey]) => {
dataArray.map(data => {
data[newKey] = data[oldKey];
delete data[oldKey];
})
});
// Check out the result:
console.log(dataArray);
Loop over it and create a new key name then delete the old one like :
jsonData.forEach((data)=>{
data.name = data.firstName;
delete data.firstName;
})

How to get JavaScript response into HTML

I've got a HTML file which requires a token to access some data (from ArcGIS Online). A separate JavaScript file should call the service and get the token. The token then needs passing into the HTML file somehow, which is the bit I'm uncertain on.
In any case, code:
JavaScript file (GetAToken.js)
var request = require('request'); // npm install request
// generate a token with your client id and client secret
function getToken(callback)
{
request.post(
{
url: 'https://www.arcgis.com/sharing/rest/oauth2/token/',
json: true,
form:
{
'f': 'json',
'client_id': '<<MY CLIENT_ID>>',
'client_secret': '<<MY CLIENT_SECRET>>',
'grant_type': 'client_credentials',
'expiration': '1440'
}
}, function (error, response, body)
{
console.log(body.access_token);
callback(body.access_token);
});
}
And the relevant bits from the HTML
<script src="GetAToken.js"></script>
</head>
<body onload="getToken()">
<div class="embed-container">
<iframe width="500"
height="400"
frameborder="0"
scrolling="no"
marginheight="0"
marginwidth="0"
title="Test Map" src="//MyMap.maps.arcgis.com/apps/webappviewer/index.html?id=LongMapID?token=I_Need_My_Token_Here&extent=1,-1,1,-1&zoom=true&scale=true&search=true&searchextent=true&legend=true&basemap_gallery=true&disable_scroll=true&theme=light">
</iframe>
</div>
</body>
</html>
If you look within the div in the HTML, that's where I need my token to go. The JavaScript apparently returns a value called access_token, and is written using node.js
EDIT
New GetAToken.js
const request = require('request'); // npm install request
const express = require('express');
const app = express();
// generate a token with your client id and client secret
//function getToken(callback)
app.get('/GetAToken', (req, res) => {
request.post(
{
url: 'https://www.arcgis.com/sharing/rest/oauth2/token/',
json: true,
form:
{
'f': 'json',
'client_id': '<<MY_CLIENT_ID>>',
'client_secret': '<<MY_CLIENT_SECRET>>',
'grant_type': 'client_credentials',
'expiration': '1440'
}
}, function (error, response, body) {
console.log(body.access_token);
callback(body.access_token);
});
});
app.listen(80);
Updated HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Title</title>
<link href="https://esri.github.io/calcite-bootstrap/assets/css/calcite-bootstrap-open.min.css" rel="stylesheet">
<style>
.footer
{
height: 6.25rem;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://esri.github.io/calcite-bootstrap/assets/js/bootstrap.min.js"></script>
<script src="https://js.arcgis.com/3.17/"></script>
<script src="GetAToken.js"></script>
<script type="text/javascript">
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function()
{
if(xhttp.readyState === 4 && xhttp.status === 200)
{
var responseJSON = JSON.parse(xhttp.responseText);
var token = responseJSON.token;
alert(token);
}
}
xhttp.open("GET", "GetAToken", true);
xhttp.send();
</script>
</head>
<body>
<style>
.embed-container
{
position: relative;
padding-bottom: 50%;
height: 0;
max-width: 100%;
}
.embed-container iframe, .embed-container object, .embed-container iframe
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
small
{
position: absolute;
z-index: 40;
bottom: 0;
margin-bottom: -15px;
}
</style>
<div class="embed-container">
<iframe width="500"
height="400"
frameborder="0"
scrolling="no"
marginheight="0"
marginwidth="0"
title="Test Map" src="//MyMap.maps.arcgis.com/apps/webappviewer/index.html?id=MyLongID&extent=1,-1,1,-1&zoom=true&scale=true&search=true&searchextent=true&legend=true&basemap_gallery=true&disable_scroll=true&theme=light">
</iframe>
</div>
</body>
</html>
You're going to want to make the response of that request to arcgis available to the client somehow. Here's an example using express:
const request = require('request'); // npm install request
const express = require('express'); // npm install express
const app = express();
app.get('/get-a-token', (req, res) =>
{
request.post(
{
url: 'https://www.arcgis.com/sharing/rest/oauth2/token/',
json: true,
form:
{
'f': 'json',
'client_id': '<<MY CLIENT_ID>>',
'client_secret': '<<MY CLIENT_SECRET>>',
'grant_type': 'client_credentials',
'expiration': '1440'
}
}, function (error, response, body)
{
console.log(body.access_token);
res.json({token: body.access_token});
});
});
app.listen(80);
Then on the client, you could do something like this to get the value from the server:
<script type="text/javascript">
// You may want to move this to another file..
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (xhttp.readyState === 4 && xhttp.status === 200) {
var responseJSON = JSON.parse(xhttp.responseText);
var token = responseJSON.token;
var iframe = document.querySelectorAll('iframe')[0]
iframe.src = "//MyMap.maps.arcgix.com/apps/webappviewer/index.html?id=LongMapID?token=" + token + "&extent=1,-1,1,-1&zoom=true&scale=true&search=true&searchextent=true&legend=true&basemap_gallery=true&disable_scroll=true&theme=light"
}
}
xhttp.open("GET", "http://yournodeserver.com/get-a-token", true);
xhttp.send();
</script>
You might want to do something to protect the /get-a-token route from being accessed by sites other than yours.
If you are serving your html file with node/express too then you could solve this by inserting the token to the html before serving it to the client instead

Categories