how to make slots output different responses - alexa

Doing some smart home skill development and my Intent utterance is "how long until my battery is {state}" State being either empty or full. I know I could do this with different intents but I wont want to have two many intents as I already have many. I basically want the user to say either full or empty in place of {state}. and then from there, depending on their answer, give different answers for full or empty. I haven't found much online so i hope you guys can help. Im also new to code.

You should create a slot for your battery state:
{
"name": "BatteryState",
"values": [
{
"id": "empty",
"name": {
"value": "empty"
}
},
{
"id": "full",
"name": {
"value": "full"
}
}
]
}
You can create it by yourself in the UI or paste in types collection in JSON editor.
Then use created slot in your intent
{
"name": "BatteryStateIntent",
"slots": [
{
"name": "batteryState",
"type": "BatteryState"
}
],
"samples": [
"how long until my battery is {batteryState}"
]
}
You can create it by yourself in the UI or paste in intents collection in JSON editor.
Then in the code:
const BatteryStateIntentHandler = {
canHandle(handlerInput) {
return (
Alexa.getRequestType(handlerInput.requestEnvelope) === "IntentRequest" &&
Alexa.getIntentName(handlerInput.requestEnvelope) === "BatteryStateIntent"
);
},
handle(handlerInput) {
const batteryStatus =
handlerInput.requestEnvelope.request.intent.slots.batteryState.value;
let speakOutput = "";
if (batteryStatus === "full") {
const timeToFull = 10; // or some sophisticated calculations ;)
speakOutput += `Your battery will be full in ${timeToFull} minutes!`;
} else if (batteryStatus === "empty") {
const timeToEmpty = 5; // or some sophisticated calculations ;)
speakOutput += `Your battery will be full in ${timeToEmpty} minutes!`;
} else {
speakOutput += "I don't know this status";
}
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
},
};
Make sure you used the same intent name as in the builder. And at the end, add created intent handler to request handlers:
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
BatteryStateIntentHandler,
// ...
)
.lambda();

Related

Discord.js outputting an entire array but want to add an emoji to correspond with each object

I am writing Guild Wars 2 commands into my bot and I have a wallet command which looks up ID's against an endpoint to give each ID a name. What I would like to do is instead of just displaying the name, I would like to display an emoji of each thing. For example, karma symbol for karma, gem symbol for gems. Adding emojis is easy, I get that part, however I can't wrap my head around how to identify what each line in the output is going to be as it is different per account that is looked up.
Here is my code so far:
var newArray = [];
for (var i = 0; i < walletArray.length; i++) {
for (var x = 0; x < currencyArray.length; x++) {
if (walletArray[i].id === currencyArray[x].id) {
if (currencyArray[x].name === "Coin") {
var bronze = String(walletArray[i].value).slice(-2)
var silver = String(walletArray[i].value).slice(-4, -2)
var gold = String(walletArray[i].value).slice(0, -4)
}
newArray.push(`${currencyArray[x].name} - ${walletArray[i].value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`)
}
}
}
The walletArray (or part of it) is:
[
{
"id": 1,
"value": 57636
},
{
"id": 2,
"value": 32969
},
{
"id": 3,
"value": 36
}
]
The currencyArray is:
{
"id": 1,
"name": "Coin",
"description": "The primary currency of Tyria. Spent at vendors throughout the world.",
"order": 101,
"icon": "https://render.guildwars2.com/file/98457F504BA2FAC8457F532C4B30EDC23929ACF9/619316.png"
},
{
"id": 2,
"name": "Karma",
"description": "Earned through various activities. Spent at vendors throughout the world.",
"order": 102,
"icon": "https://render.guildwars2.com/file/94953FA23D3E0D23559624015DFEA4CFAA07F0E5/155026.png"
},
{
"id": 3,
"name": "Laurel",
"description": "Earned through the Log-in Reward Chest. Spent in major cities. Used to purchase various rewards.",
"order": 104,
"icon": "https://render.guildwars2.com/file/A1BD345AD9192C3A585BE2F6CB0617C5A797A1E2/619317.png"
}
The output is:
Wallet command output
I have no idea if I am even approaching this correctly but I just want it to look a bit nicer! It is fully functional just we can always improve things. My JS is not the best, it was learned during lockdown as something to do and was learned almost entirely from this website!
Any help would be appreciated, cheers.
Well, if I understand your problem correctly, you know each line of the output is gonna be, because of currencyArray.name. The solution should be something like:
var newArray = [];
for (var i = 0; i < walletArray.length; i++) {
for (var x = 0; x < currencyArray.length; x++) {
if (walletArray[i].id === currencyArray[x].id) {
var emote;
if (currencyArray[x].name === "Coin") {
emote = "🪙"
var bronze = String(walletArray[i].value).slice(-2)
var silver = String(walletArray[i].value).slice(-4, -2)
var gold = String(walletArray[i].value).slice(0, -4)
}
else if (currencyArray[x].name === "Karma") {
emote = "☯️"
}
else if (currencyArray[x].name === "Laurel") {
emote = "💳"
}
newArray.push(`${emote} ${currencyArray[x].name} - ${walletArray[i].value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`)
}
}
}
Of course, use any emotes you wish.
Maybe you want to use a Map. discord.js names it Collection but they are pretty much the same.
let myMap = new Map();
myMap.set('key', 'emoji')
let emoji1 = myMap.get('key') //'emoji'
The 'key' is linked to the value which you can get with the Map.get method

How to display text on MapBox at specific coordinates?

I am currently using MapBox GL JS in my React project.
I want to know how to display some text at specific coordinates after an interaction is over. I get the coordinates of the location from a function getMinCoords()
My current code is as follows
stop() {
let nextState = this.state;
if (nextState !== 'Complete') {
nextState = 'Stop';
}
if (this.vertices.length > 2) {
this.annotation.geometries = [{
type: 'Polygon',
coordinates: this.GetPolygonCoordinates(),
properties: {
annotationType: 'polygon',
},
}];
} else {
this.annotation.geometries = [];
}
console.log(this.getMinCoords());
this.map.off('click', this.onClickCallback);
this.setState(nextState);
this.flushState();
}
The function which takes care of annotations is as follows:
this.geometries.forEach((geometry) => {
switch (geometry.type) {
case 'Point':
case 'LineString':
case 'Polygon': {
const styling = GetStyles(geometry, styles);
const feature = GetFeatureFromGeometry(geometry, this.properties);
if (this.properties.annotationType === 'label') {
styling.textAnchor = 'center';
}
feature.properties = { ...feature.properties, ...styleProps };
features.push(feature);
break;
}
Before the state is flushed, I want to display the area at the coordinates returned by getMinCoords. I have another function getArea(), which returns the area. I just need to display it on the map
You can create an empty Layer once your map is instantiated with empty source like below:
Code Snippet:
//Empty Source
const textGeoJsonSource = {
type: 'geojson',
data: featureCollection //Initially this is empty
};
//Text Layer with textGeoJsonSource
const sectionTextLayer: mapboxgl.Layer = {
"id": "sectionTextLayer",
"type": "symbol",
"source": textGeoJsonSource,
"paint": {
"text-color": textColor, //Color of your choice
"text-halo-blur": textHaloBlur,
"text-halo-color": textHaloColor,
"text-halo-width": textHaloWidth,
"text-opacity": textOpacity
},
"layout": {
"text-field": ['get', 't'], //This will get "t" property from your geojson
"text-font": textFontFamily,
"text-rotation-alignment": "auto",
"text-allow-overlap": true,
"text-anchor": "top"
}
};
this.mapInstance.addLayer(sectionTextLayer);
Then later on set the source of "textGeoJsonSource" to below once you have the coordinates( like getMinCoords in your case ):
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [ //Pass your coordinates here
5.823,
-6.67
]
},
"properties": {
"t": "18C" //Text you want to display on Map
}
}
]
}
Please note few things:
Your feature collection will need point coordinates in order to show text on Map on that point. If you have a polygon, first get centroid of that polygon for that you can use turf:
http://turfjs.org/docs/#centroid
Helpful Links: Centering text label in mapbox-gl-js?

How to read objects and store into array

I made an http request and got back e.g the below json. I want to read the cars and the shoes objects into separate arrays at the time of the http request.
json
{
"id": 9,
"name": "Zlatan",
"cars": [
{
"type": "ford",
"year": "2019"
},
{
"type": "audi",
"year": "2017"
}
]
"shoes": [
{
"brand": "adidas",
"status": "old"
},
{
"brand": "timberland",
"status": "new"
}
]
}
comp.ts
cars = [];
shoes = [];
//......
getZlatan() {
return this.httpService.getInfo()
.subscribe( data => {
this.objZlatan = data; //this part holds the json obj above
this.cars ....//what to add here
this.shoes ....// here too.
} );
}
Or is there a cleaner way to load the arrays at http request?
Access the cars and shoes properties of the data with simple dot-notation. It might be ideal to check if the data returned is not null with if(condition here) and then perform your logic. If you have more objects and want to bring all cars and shoes under one array then you have to loop through.
getZlatan() {
return this.httpService.getInfo()
.subscribe(data => {
this.objZlatan = data;
this.cars = this.objZlatan.cars;
this.shoes = this.objZlatan.shoes;
});
}
Just use . and type names to access cars and shoes. Let me show an example:
return this.httpService.getInfo()
.subscribe( data => {
this.objZlatan = data; //this part holds the json obj above
this.cars = data.cars;
this.shoes =data.shoes;
} );

Is there any way to update state by find Item and replace on a nested state?

I am building an order functionality of my modules in the component state on react
so the state object looks like that
"activity": {
"name": "rewwerwer",
"description": "werwerwerwerwer",
"modules": [
{
"name": "Text",
"order": 1,
"module_id": 1612,
},
{
"name": "Text2",
"order" 2,
"module_id": 1592,
}
]
}
handleSortUp = (moduleid ,newOrder) => {
const { modules } = this.state.activity;
const module = modules.find(element => element.module_id === moduleid);//Thios returns the correct object
this.setState({ activity: { ...this.state.activity.modules.find(element => element.module_id === moduleid), order: newOrder } });
}
I tried this but it updates the order field and object
but also removes all other objects from modules array :<
I like just to replace only the order field on each module by module id
and leave rest data there
the required response from the state that i need when the handleSortUp(1612,14); is fired
handleSortUp(1612,2);
{
"name": "rewwerwer",
"description": "werwerwerwerwer",
"modules": [
{
"name": "Text",
"order": 2,
"module_id": 1612,
},
{
"name": "Text2",
"order": 1,
"module_id": 1592,
}
]
}
I can do this on a simple array the question is how to update the State on react
Also the one way to change the order is answered fine but how also to change the field that had that order registered
So when we fire Change Item 1 order to 2 the Item 2 needs to take the Order 1
Thank you
Sure! This would be a great place to use the built-in .map method available for arrays. Consider the following example.
let array = [{order: 1, type: "food"}, {order: 2, type: "notfood"} ]
const newArray = array.map((item) => {
//CHECK TO SEE IF THIS IS THE ITEM WE WANT TO UPDATE
if(item.order == 1){
return {
...item,
newField: "newData"
}
} else {
return item
}
})
Output is:
[{order: 1, type: "food", newField: "newData"}
{order: 2, type: "notfood"}]
So yes you could totally update the module you're looking for without mutating the rest of your array. Then use your findings to update the component state using some good ol spread.
this.setState({
activity: {
...this.state.activity,
modules: newArray}
})
Of course they get all eliminated. Pay attention to what you wrote here:
this.setState({ activity: { ...this.state.activity.modules.find(element => element.module_id === moduleid), order: newOrder } });
What are you doing with that find? Let's see what Array.prototype.find() returns: https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Array/find
It returns an index, why would you insert an index into the state?
The answer partially came from yourfavoritedev.
As he said you can use the built-in Array.prototype.map() and do it like this:
handleSortUp = (moduleid ,newOrder) => {
const { modules } = this.state.activity;
const newModules = modules.map(module => module.module_id === moduleid ? { ...module, order: newOrder } : module)
this.setState({ activity: { ...this.state.activity, modules: newModules } });
}
This should work, let me know but I strongly advice to ask me or search on the web if you don't understand what is happening there (syntactically or semantically speaking).

How to fetch data from json using Reactjs

I know this is very basic. but i would appreciate if anyone can help me understanding on how to fetch data from json using React js.
I have just started to learn React so was just curious to know if there are any ways to fetch data from complex json using this.
I have tried to follow React Tutorial
I am trying to fetch data from 2nd level keys in a json. I was able to do that using Object.keys, but I am not sure what the issue is here when i am trying to apply it to my dataset. I am just unable to get anything when i try the commented dataset which is not that different from the other dataset. Can Object.keys be applied to datasets where there are more than one key? Can anyone please help?
Please check my fiddle
Here is my code
var SearchStock = React.createClass({
getInitialState: function() {
return {searchString: ''};
},
handleChange: function(e) {
this.setState({searchString: e.target.value});
},
render: function() {
var stocks = this.props.items, searchString = this.state.searchString.trim().toLowerCase();
if (searchString.length > 0) {
stocks = stocks.filter(function(l) {
// return l.name.toLowerCase().match(searchString);
return l[Object.keys(l)[0]]["name"].toLowerCase().match(searchString);
});
}
return <div >
< input type = "text" value = {this.state.searchString} onChange = {this.handleChange} placeholder = "Type here" / >
< ul >
{stocks.map(function(l) {
return <li > {l[Object.keys(l)[0]]["name"]} < /li>
// return <li > {l[Object.keys(l)[0]]["name"]} < /li>
})
}
< /ul>
< /div>;
}
});
// var stocks = [{"F": {"symbol": "F", "name": "Ford Motor", "bidPrice": 13.41, "askPrice": 13.36}}, {"GE": {"symbol": "GE", "name": "General Electric", "bidPrice": 32.33, "askPrice": 32.39}}, {"JNJ: {"symbol": "JNJ", "name": "Johnson \u0026 Johnson", "bidPrice": 121.0, "askPrice": 123.0,}}];
var stocks = [{"symbol": {"symbol": "F", "name": "Ford Motors"}, "name": "Ford Motor", "bidPrice": 13.41, "askPrice": 13.36}, {"symbol": {"symbol": "GE", "name": "General Electronics"}, "name": "General Electric", "bidPrice": 32.33, "askPrice": 32.39}, {"symbol": {"symbol": "JNJ", "name": "Johnson \u0026 Johnson"}, "name": "Johnson \u0026 Johnson", "bidPrice": 121.0, "askPrice": 123.0,}];
ReactDOM.render( < SearchStock items = {stocks} />,document.getElementById('container'));
My Aim is to build a simple single page app in which we can search data from json using the key.symbol, so i am adding another level to the data so that when i build my api i can just put it there using the symbol.
I would appreciate if anyone can help me out with this. Sorry for changing my question in the middle. And thanks for pointing me in the right direction.
implement that in the componentDidMount method of your Stock element.
Something like this:
var Stock = React.createClass({
...
render: function() {
...
},
componentDidMount: function() {
let url = 'myStockApi/' + this.props.symbol;
this.serverRequest = $.get(url, function(result) {
let quote = result;
this.setState({
quote
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
});
Check out the documentation here.
I was able to find my answer from here . I have update my post. Please check the code in my post.

Resources