Ace editor autocomplete uploads extra-records - angularjs

I added ui-ace editor to the my application with angular. Instead of requesting words every time, I get a json 1 time, during application initiation.
Example of json-file:
[
{
"Word": "Do {int} + {int}",
"Meta": "Implemented"
},
{
"Word": "Line3",
"Meta": "Not-implemented"
},
{
"Word": "Line2",
"Meta": "Not-implemented"
},
{
"Word": "Line4",
"Meta": "Not-implemented"
},
{
"Word": "444",
"Meta": "Not-implemented"
},
{
"Word": "E1",
"Meta": "Not-implemented"
},
{
"Word": "E2",
"Meta": "Not-implemented"
},
{
"Word": "E1Try",
"Meta": "Not-implemented"
},
{
"Word": "E3",
"Meta": "Not-implemented"
},
{
"Word": "E4444",
"Meta": "Not-implemented"
}
]
The issue is that some of words are listed in autocomplete more than ones, take a look on a screenshot: http://take.ms/N8BFZ .
Here's how I load ace-editor, where ctrl.listStepLines is an object which contains json-response from API:
$scope.aceLoaded = function(_editor){
// Editor part
var _session = _editor.getSession();
var _renderer = _editor.renderer;
_editor.$blockScrolling = Infinity;
_editor.setOptions({
minLines: 10,
maxLines: 40,
wrap: true,
firstLineNumber: 1,
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true
})
var langTools = ace.require("ace/ext/language_tools");
var rhymeCompleter = {
getCompletions: function (editor, session, pos, prefix, callback) {
if (prefix.length === 0) { callback(null, []); return }
callback(null, ctrl.listStepLines.map(function (ea) {
return { name: ea.Word, value: ea.Word, meta: ea.Meta }
}));
}
}
langTools.addCompleter(rhymeCompleter);
};

The issue was that angularjs loaded my function a lot of times and ace editor had 14 similar completers. I refactored my code and create a separate function for completer adding which is called only one time.
ctrl.addAutoCompleter();
function init() {
ctrl.addAutoCompleter = function () {
var langTools = ace.require("ace/ext/language_tools");
var stepLineCompleter = {
getCompletions: function (_editor, session, pos, prefix, callback) {
if (prefix.length === 0) { callback(null, []); return }
callback(null, ctrl.listStepLines.map(function (ea) {
return { name: ea.Word, value: ea.Word, meta: ea.Meta }
}));
}
}
langTools.addCompleter(stepLineCompleter);
}
};

Related

How do I sort this array by date?

I'm trying to sort the dates from this external API in my latestResults array by latest on top to oldest on bottom but can't seem to figure out how.
Right now they're displayed with the oldest date first and it's working fine, but it's in the wrong order for me.
I tried using result in latestResults.reverse() but that just reverses the 7 items currently in the array.
HTML:
<div v-for="result in latestResults" v-bind:key="result.latestResults">
<small">{{ result.utcDate }}</small>
</div>
Script:
<script>
import api from '../api'
export default {
data () {
return {
latestResults: [],
limit: 7,
busy: false,
loader: false,
}
},
methods: {
loadMore() {
this.loader = true;
this.busy = true;
api.get('competitions/PL/matches?status=FINISHED')
.then(response => { const append = response.data.matches.slice(
this.latestResults.length,
this.latestResults.length + this.limit,
this.latestResults.sort((b, a) => {
return new Date(b.utcDate) - new Date(a.utcDate);
})
);
setTimeout(() => {
this.latestResults = this.latestResults.concat(append);
this.busy = false;
this.loader = false;
}, 500);
});
}
},
created() {
this.loadMore();
}
}
</script>
The JSON where I'm getting matches like this that has utcDate:
{
"count": 205,
"filters": {
"status": [
"FINISHED"
]
},
"competition": {
"id": 2021,
"area": {
"id": 2072,
"name": "England"
},
"name": "Premier League",
"code": "PL",
"plan": "TIER_ONE",
"lastUpdated": "2021-02-01T16:20:10Z"
},
"matches": [
{
"id": 303759,
"season": {
"id": 619,
"startDate": "2020-09-12",
"endDate": "2021-05-23",
"currentMatchday": 22
},
"utcDate": "2020-09-12T11:30:00Z",
"status": "FINISHED",
"matchday": 1,
"stage": "REGULAR_SEASON",
"group": "Regular Season",
"lastUpdated": "2020-09-13T00:08:13Z",
"odds": {
"msg": "Activate Odds-Package in User-Panel to retrieve odds."
},
},

Response duplicated but the count shows as 1

Using Dynamoose ORM with Serverless. I have a scenario where I'm finding user information based on recommendation.
The response is as follows
{
"data": {
"results": [
{
"specialTip": "Hello World",
"recommendation": "Huli ka!",
"poi": {
"uuid": "poi_555",
"name": "Bukit Panjang",
"images": [
{
"url": "facebook.com",
"libraryUuid": "2222",
"uuid": "9999"
}
]
},
"uuid": "i_8253578c-600d-4dfd-bd40-ce5b9bb89067",
"headline": "Awesome",
"dataset": "attractions",
"insiderUUID": "i_c932e85b-0aee-4462-b930-962f555b64bd",
"insiderInfo": [
{
"gender": "m",
"funFacts": [
{
"type": "knock knock!",
"answer": "Who's there?"
}
],
"profileImage": "newImage.jpg",
"shortDescription": "Samething",
"fullDescription": "Whatever Description",
"interests": [
"HELLO",
"WORLD"
],
"tribes": [
"HELLO",
"WORLD"
],
"uuid": "i_c932e85b-0aee-4462-b930-962f555b64bd",
"personalities": [
"HELLO",
"WORLD"
],
"travelledCities": [
"HELLO",
"WORLD"
]
}
]
},
{
"specialTip": "Hello World",
"recommendation": "Huli ka!",
"poi": {
"uuid": "poi_555",
"name": "Bukit Panjang",
"images": [
{
"url": "facebook.com",
"libraryUuid": "2222",
"uuid": "9999"
}
]
},
"uuid": "i_8253578c-600d-4dfd-bd40-ce5b9bb89067",
"headline": "Awesome",
"dataset": "attractions",
"insiderUUID": "i_c932e85b-0aee-4462-b930-962f555b64bd",
"insiderInfo": [
{
"gender": "m",
"funFacts": [
{
"type": "knock knock!",
"answer": "Who's there?"
}
],
"profileImage": "newImage.jpg",
"shortDescription": "Samething",
"fullDescription": "Whatever Description",
"interests": [
"HELLO",
"WORLD"
],
"tribes": [
"HELLO",
"WORLD"
],
"uuid": "i_c932e85b-0aee-4462-b930-962f555b64bd",
"personalities": [
"HELLO",
"WORLD"
],
"travelledCities": [
"HELLO",
"WORLD"
]
}
]
}
],
"count": 1
},
"statusCode": 200
}
Not sure where I'm going wrong as the items in the response seems to be duplicated but the count is 1.
Here is the code
module.exports.index = (_event, _context, callback) => {
Recommendation.scan().exec((_err, recommendations) => {
if (recommendations.count == 0) {
return;
}
let results = [];
recommendations.forEach((recommendation) => {
Insider.query({uuid: recommendation.insiderUUID}).exec((_err, insider) => {
if (insider.count == 0) {
return;
}
recommendation.insiderInfo = insider;
results.push(recommendation);
});
});
const response = {
data: {
results: results,
count: results.count
},
statusCode: 200
};
callback(null, response);
});
};
EDIT: My previous code ignored the fact that your "Insider" query is asynchronous. This new code handles that and matches your edit.
const async = require('async'); // install async with 'npm install --save async'
[...]
module.exports.index = (_event, _context, callback) => {
Recommendation.scan().exec((_err, recommendations) => {
if (_err) {
console.log(_err);
return callback(_err);
}
if (recommendations.count == 0) {
const response = {
data: {
results: [],
count: 0
},
statusCode: 200
};
return callback(null, response);
}
let results = [];
async.each(recommendations, (recommendation, cb) => { // We need to handle each recommendation asynchronously...
Insider.query({uuid: recommendation.insiderUUID}).exec((_err, insider) => { // because this is asynchronous
if (_err) {
console.log(_err);
return callback(_err);
}
if (insider.count == 0) {
return cb(null);
}
recommendation.insiderInfo = insider;
results.push(recommendation);
return cb(null);
});
}, (err) => { // Once all items are handled, this is called
if (err) {
console.log(err);
return callback(err);
}
const response = { // We prepare our response
data: {
results: results, // Results may be in a different order than in the initial `recommendations` array
count: results.count
},
statusCode: 200
};
callback(null, response); // We call our main callback only once
});
});
};
Initial (partly incorrect) answer, for reference.
You are pushing the result of your mapping into the object that you are currently mapping and callback is called more than once here. That's a pretty good amount of unexpected behavior material.
Try the following:
let results = [];
recommendations.forEach((recommendation) => {
Insider.query({uuid: recommendation.insiderUUID}).exec((_err, insider) => {
if (insider.count == 0) {
return;
}
recommendation.insiderInfo = insider;
results.push(recommendation);
});
});
let response = {
data: {
results: results,
count: results.count
},
statusCode: 200
};
callback(null, response);

Alexa Developer Console replying with "There was a problem with the requested skill's response"

I have been trying to resolve this issue for the past couple of hours with no success. Here is my code:
Lambda code:
/*eslint-disable func-names */
/* eslint quote-props: ["error", "consistent"]*/
// There are three sections, Text Strings, Skill Code, and Helper Function(s).
// You can copy and paste the contents as the code for a new Lambda function, using the alexa-skill-kit-sdk-factskill template.
// This code includes helper functions for compatibility with versions of the SDK prior to 1.0.9, which includes the dialog directives.
// 1. Text strings =====================================================================================================
// Modify these strings and messages to change the behavior of your Lambda function
let speechOutput;
let reprompt;
let welcomeOutput = "Welcome to Tanpura! You can ask me to play at any pitch. How can I help you today?";
let welcomeReprompt = "sample re-prompt text";
// 2. Skill Code =======================================================================================================
"use strict";
const Alexa = require('alexa-sdk');
const APP_ID = undefined; // TODO replace with your app ID (OPTIONAL).
speechOutput = '';
const handlers = {
'LaunchRequest': function () {
this.emit(':ask', welcomeOutput, welcomeReprompt);
},
'AMAZON.HelpIntent': function () {
speechOutput = 'You can ask me to play at any pitch, such as C, C sharp, D, D sharp, and so on. How can I help you?';
reprompt = '';
this.emit(':ask', speechOutput, reprompt);
},
'AMAZON.CancelIntent': function () {
speechOutput = 'Would you like me to play another pitch?';
this.emit(':tell', speechOutput);
},
'AMAZON.StopIntent': function () {
speechOutput = 'I hope I helped you. Goodbye!';
this.emit(':tell', speechOutput);
},
'SessionEndedRequest': function () {
speechOutput = '';
//this.emit(':saveState',true);//uncomment to save attributes to db on session end
this.emit(':tell', speechOutput);
},
'AMAZON.FallbackIntent': function () {
speechOutput = '';
//any intent slot variables are listed here for convenience
//Your custom intent handling goes here
speechOutput = "I currently do not support your request. However, you can ask me to play at any pitch, and I will do so. How can I help?";
this.emit(":ask", speechOutput, speechOutput);
},
'AMAZON.NavigateHomeIntent': function () {
speechOutput = '';
//any intent slot variables are listed here for convenience
//Your custom intent handling goes here
speechOutput = "Welcome to Tanpura! You can ask me to play at any pitch. How can I help you today?";
this.emit(":ask", speechOutput, speechOutput);
},
'PlayNoteIntent': function () {
speechOutput = '';
//any intent slot variables are listed here for convenience
let noteSlot = resolveCanonical(this.event.request.intent.slots.note);
console.log("User selected pitch: " + noteSlot);
let accidentalSlot = resolveCanonical(this.event.request.intent.slots.accidental);
console.log("User selected accidental: " + accidentalSlot);
var notes = {
'a': {
'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Gsharp.mp3',
'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_A.mp3',
'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Asharp.mp3'
},
'b': {
'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Asharp.mp3',
'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_B.mp3',
'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_C.mp3'
},
'c': {
'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_B.mp3',
'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_C.mp3',
'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Csharp.mp3'
},
'd': {
'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Csharp.mp3',
'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_D.mp3',
'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Dsharp.mp3'
},
'e': {
'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Dsharp.mp3',
'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_E.mp3',
'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_F.mp3'
},
'f': {
'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_E.mp3',
'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_F.mp3',
'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Fsharp.mp3'
},
'g': {
'flat': 'https://s3.amazonaws.com/tanpuranew/tanpura_Fsharp.mp3',
'natural': 'https://s3.amazonaws.com/tanpuranew/tanpura_G.mp3',
'sharp': 'https://s3.amazonaws.com/tanpuranew/tanpura_Gsharp.mp3'
}
}
var note = noteSlot.toLowerCase();
var speechReprompt = "";
if (noteSlot && notes[note]){
var audio = '';
var accidental = 'natural';
if(accidentalSlot && accidental.indexOf(accidentalSlot) > -1){
accidental = accidentalSlot;
}
var audioSrc = notes[note][accidental];
speechOutput = "Ok. I will play " + noteSlot + accidental + <audio src="' + audioSrc + '" />;
speechReprompt = "Would you like me to continue playing?";
}
else{
speechOutput = "The note you have requested is not supported yet.";
speechReprompt = "However, Tanpura does support A, B, C, D, E, F, G, and all of the accidentals in between.";
}
//Your custom intent handling goes here
this.emit(":ask", speechOutput, speechOutput);
},
'Unhandled': function () {
speechOutput = "Tanpura didn't quite understand what you wanted. Please try rephrasing your request.";
this.emit(':ask', speechOutput, speechOutput);
}
};
exports.handler = (event, context) => {
const alexa = Alexa.handler(event, context);
alexa.appId = APP_ID;
// To enable string internationalization (i18n) features, set a resources object.
//alexa.resources = languageStrings;
alexa.registerHandlers(handlers);
//alexa.dynamoDBTableName='DYNAMODB_TABLE_NAME';//uncomment this line to save attributes to DB
alexa.execute();
};
// END of Intent Handlers {} ========================================================================================
// 3. Helper Function =================================================================================================
function resolveCanonical(slot){
//this function looks at the entity resolution part of request and returns the slot value if a synonyms is provided
let canonical;
try{
canonical = slot.resolutions.resolutionsPerAuthority[0].values[0].value.name;
}catch(err){
console.log(err.message);
canonical = slot.value;
};
return canonical;
};
function delegateSlotCollection(){
console.log("in delegateSlotCollection");
console.log("current dialogState: "+this.event.request.dialogState);
if (this.event.request.dialogState === "STARTED") {
console.log("in Beginning");
let updatedIntent= null;
// updatedIntent=this.event.request.intent;
//optionally pre-fill slots: update the intent object with slot values for which
//you have defaults, then return Dialog.Delegate with this updated intent
// in the updatedIntent property
//this.emit(":delegate", updatedIntent); //uncomment this is using ASK SDK 1.0.9 or newer
//this code is necessary if using ASK SDK versions prior to 1.0.9
if(this.isOverridden()) {
return;
}
this.handler.response = buildSpeechletResponse({
sessionAttributes: this.attributes,
directives: getDialogDirectives('Dialog.Delegate', updatedIntent, null),
shouldEndSession: false
});
this.emit(':responseReady', updatedIntent);
} else if (this.event.request.dialogState !== "COMPLETED") {
console.log("in not completed");
// return a Dialog.Delegate directive with no updatedIntent property.
//this.emit(":delegate"); //uncomment this is using ASK SDK 1.0.9 or newer
//this code necessary is using ASK SDK versions prior to 1.0.9
if(this.isOverridden()) {
return;
}
this.handler.response = buildSpeechletResponse({
sessionAttributes: this.attributes,
directives: getDialogDirectives('Dialog.Delegate', null, null),
shouldEndSession: false
});
this.emit(':responseReady');
} else {
console.log("in completed");
console.log("returning: "+ JSON.stringify(this.event.request.intent));
// Dialog is now complete and all required slots should be filled,
// so call your normal intent handler.
return this.event.request.intent;
}
}
function randomPhrase(array) {
// the argument is an array [] of words or phrases
let i = 0;
i = Math.floor(Math.random() * array.length);
return(array[i]);
}
function isSlotValid(request, slotName){
let slot = request.intent.slots[slotName];
//console.log("request = "+JSON.stringify(request)); //uncomment if you want to see the request
let slotValue;
//if we have a slot, get the text and store it into speechOutput
if (slot && slot.value) {
//we have a value in the slot
slotValue = slot.value.toLowerCase();
return slotValue;
} else {
//we didn't get a value in the slot.
return false;
}
}
//These functions are here to allow dialog directives to work with SDK versions prior to 1.0.9
//will be removed once Lambda templates are updated with the latest SDK
function createSpeechObject(optionsParam) {
if (optionsParam && optionsParam.type === 'SSML') {
return {
type: optionsParam.type,
ssml: optionsParam['speech']
};
} else {
return {
type: optionsParam.type || 'PlainText',
text: optionsParam['speech'] || optionsParam
};
}
}
function buildSpeechletResponse(options) {
let alexaResponse = {
shouldEndSession: options.shouldEndSession
};
if (options.output) {
alexaResponse.outputSpeech = createSpeechObject(options.output);
}
if (options.reprompt) {
alexaResponse.reprompt = {
outputSpeech: createSpeechObject(options.reprompt)
};
}
if (options.directives) {
alexaResponse.directives = options.directives;
}
if (options.cardTitle && options.cardContent) {
alexaResponse.card = {
type: 'Simple',
title: options.cardTitle,
content: options.cardContent
};
if(options.cardImage && (options.cardImage.smallImageUrl || options.cardImage.largeImageUrl)) {
alexaResponse.card.type = 'Standard';
alexaResponse.card['image'] = {};
delete alexaResponse.card.content;
alexaResponse.card.text = options.cardContent;
if(options.cardImage.smallImageUrl) {
alexaResponse.card.image['smallImageUrl'] = options.cardImage.smallImageUrl;
}
if(options.cardImage.largeImageUrl) {
alexaResponse.card.image['largeImageUrl'] = options.cardImage.largeImageUrl;
}
}
} else if (options.cardType === 'LinkAccount') {
alexaResponse.card = {
type: 'LinkAccount'
};
} else if (options.cardType === 'AskForPermissionsConsent') {
alexaResponse.card = {
type: 'AskForPermissionsConsent',
permissions: options.permissions
};
}
let returnResult = {
version: '1.0',
response: alexaResponse
};
if (options.sessionAttributes) {
returnResult.sessionAttributes = options.sessionAttributes;
}
return returnResult;
}
function getDialogDirectives(dialogType, updatedIntent, slotName) {
let directive = {
type: dialogType
};
if (dialogType === 'Dialog.ElicitSlot') {
directive.slotToElicit = slotName;
} else if (dialogType === 'Dialog.ConfirmSlot') {
directive.slotToConfirm = slotName;
}
if (updatedIntent) {
directive.updatedIntent = updatedIntent;
}
return [directive];
}
Alexa Developer JSON Input:
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.1456bfda-a9d3-457f-88a7-bc5387d774db",
"application": {
"applicationId": "amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2"
},
"user": {
"userId": "amzn1.ask.account.AGD7V7GZTLU4DQH623OMU5MUBR2FGWXKDVW2OPNYYRWKIYJCHQBCSKVNQHEPOEXQWO33Q4OTJ6LSIRLYT3TN33OAK3W7LLNNYPU5S3MVKPMPNH2XDWYJ7DBWCFZRXY4STCPFKVL2FADYZE4TXS53Z5AXBPN6344R6VG6GD365TFQTCPPKABC5IKM46UZXUX3BPR4TQ4KEYO6LTA"
}
},
"context": {
"System": {
"application": {
"applicationId": "amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2"
},
"user": {
"userId": "amzn1.ask.account.AGD7V7GZTLU4DQH623OMU5MUBR2FGWXKDVW2OPNYYRWKIYJCHQBCSKVNQHEPOEXQWO33Q4OTJ6LSIRLYT3TN33OAK3W7LLNNYPU5S3MVKPMPNH2XDWYJ7DBWCFZRXY4STCPFKVL2FADYZE4TXS53Z5AXBPN6344R6VG6GD365TFQTCPPKABC5IKM46UZXUX3BPR4TQ4KEYO6LTA"
},
"device": {
"deviceId": "amzn1.ask.device.AFHBRIBVUWYIR2ESXPKWP3G3PHYK4W5VW4NF55KH5ZXD27WMSPBPU7YLJQJWM2YQDZBH7VWGXCLNQKESUNWWGI6CJUWUUSWUKVBZWZC5LBNXMCDY2IOZAZUYWHYXT5VLLA7XC3OP2WY7RXE2LPRHM5E4BIMR662M5MZKJH4WRPUFS3HVIFRDK",
"supportedInterfaces": {}
},
"apiEndpoint": "https://api.amazonalexa.com",
"apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLjBjMjM3MTMyLTg4MTUtNDAyNS1hMjNmLWNhNmRmNjg4YmNkMiIsImV4cCI6MTUzOTU1MzE2NywiaWF0IjoxNTM5NTQ5NTY3LCJuYmYiOjE1Mzk1NDk1NjcsInByaXZhdGVDbGFpbXMiOnsiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUZIQlJJQlZVV1lJUjJFU1hQS1dQM0czUEhZSzRXNVZXNE5GNTVLSDVaWEQyN1dNU1BCUFU3WUxKUUpXTTJZUURaQkg3VldHWENMTlFLRVNVTldXR0k2Q0pVV1VVU1dVS1ZCWldaQzVMQk5YTUNEWTJJT1pBWlVZV0hZWFQ1VkxMQTdYQzNPUDJXWTdSWEUyTFBSSE01RTRCSU1SNjYyTTVNWktKSDRXUlBVRlMzSFZJRlJESyIsInVzZXJJZCI6ImFtem4xLmFzay5hY2NvdW50LkFHRDdWN0daVExVNERRSDYyM09NVTVNVUJSMkZHV1hLRFZXMk9QTllZUldLSVlKQ0hRQkNTS1ZOUUhFUE9FWFFXTzMzUTRPVEo2TFNJUkxZVDNUTjMzT0FLM1c3TExOTllQVTVTM01WS1BNUE5IMlhEV1lKN0RCV0NGWlJYWTRTVENQRktWTDJGQURZWkU0VFhTNTNaNUFYQlBONjM0NFI2Vkc2R0QzNjVURlFUQ1BQS0FCQzVJS000NlVaWFVYM0JQUjRUUTRLRVlPNkxUQSJ9fQ.KAHvIOOUP4k-73lNMxRnOToYjrUbeHuLRDQGzMFi9dVEiwc2QpvpMZpLNpG5rCtoqB2-OfC48KbK5u67nW6X9QO6DSoNTBfPKUatIHB6pUWbArdv-FliUO69SQMomjLtLzC86_jnZ8TqvNavjb5I5hOGnmCe5Fv2IY5HgBw0h07Dq3ZT4i_4edcnhX9zYJretTEydF0L3JA7GTithgtAGFxbBqbiDTKRMlaGUGBWAkZkHy8FPWsAmvfTwRaNL7F3LAEbGH2QJlyoPQR7jYij7CsnlRAEv-3Ur1kFaMEdhDNA9fcn2JI4TVf1umy0fL66dHWq3omk2p5I4FyrJ3a8SQ"
}
},
"request": {
"type": "IntentRequest",
"requestId": "amzn1.echo-api.request.80cc2899-2fa2-4828-99ba-1c25d8cce05b",
"timestamp": "2018-10-14T20:39:27Z",
"locale": "en-US",
"intent": {
"name": "PlayNoteIntent",
"confirmationStatus": "NONE",
"slots": {
"note": {
"name": "note",
"value": "an",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2.Note",
"status": {
"code": "ER_SUCCESS_NO_MATCH"
}
}
]
},
"confirmationStatus": "NONE",
"source": "USER"
},
"accidental": {
"name": "accidental",
"value": "e",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.0c237132-8815-4025-a23f-ca6df688bcd2.accidental",
"status": {
"code": "ER_SUCCESS_NO_MATCH"
}
}
]
},
"confirmationStatus": "NONE",
"source": "USER"
}
}
}
}
}
And finally the Skill's JSON:
{
"interactionModel": {
"languageModel": {
"invocationName": "tanpura",
"intents": [
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
},
{
"name": "PlayNoteIntent",
"slots": [
{
"name": "note",
"type": "Note"
},
{
"name": "accidental",
"type": "accidental"
}
],
"samples": [
"for an {note} {accidental}",
"for a {note} {accidental}",
"play {note} {accidental}",
"Start an {note} {accidental}",
"Give me an {note} {accidental}",
"Make an {note} {accidental}",
"Put on an {note} {accidental}",
"Sing at an {note} {accidental}",
"Sing at a {note} {accidental}",
"Create an {note} {accidental}",
"Lets hear an {note} {accidental}",
"Play an {note} {accidental}",
"Lets hear a {note} {accidental}",
"Sing at {note} {accidental}",
"Create a {note} {accidental}",
"Make a {note} {accidental}",
"Put on a {note} {accidental}",
"Initiate a {note} {accidental}",
"Give me a {note} {accidental}",
"Start a {note} {accidental}",
"Play a {note} {accidental}"
]
}
],
"types": [
{
"name": "Note",
"values": [
{
"name": {
"value": "B"
}
},
{
"name": {
"value": "A#"
}
},
{
"name": {
"value": "A"
}
},
{
"name": {
"value": "G#"
}
},
{
"name": {
"value": "G"
}
},
{
"name": {
"value": "F"
}
},
{
"name": {
"value": "E"
}
},
{
"name": {
"value": "D#"
}
},
{
"name": {
"value": "D"
}
},
{
"name": {
"value": "C#"
}
},
{
"name": {
"value": "C"
}
}
]
},
{
"name": "accidental",
"values": [
{
"name": {
"value": "natural"
}
},
{
"name": {
"value": "flat"
}
},
{
"name": {
"value": "sharp"
}
}
]
}
]
}
}
}
The code was working initially, but after I made a couple of edits to the Lambda code, I was getting the same reply again and again, which made no sense. I think that the problem may lie in the fact that I added an extra value for the accidental value, and I added a natural value before rebuilding my Lambda code in the skillinator.io site. Any help would be much appreciated as I have been struggling with this code all day.
"There was a problem with the requested skill's responseā€ means that there is something wrong with the response json. It might be null or invalid.
In your case, this line throws an error because your string concatenation is not right.
speechOutput = "Ok. I will play " + noteSlot + accidental + <audio src="' + audioSrc + '" />;
Change it to :
speechOutput = "Ok. I will play " + noteSlot + accidental + "<audio src=\"" + audioSrc + "\" />";

Node async map not excecuting properly inside redux action

I connect to an API which is returning data in this format:
[
{
"id": 23,
"name": "11:40AM July 2",
"airplayEnabled": false,
"airplayCodeEnabled": true,
"type": 0,
"groups": [
{
"id": 4,
"name": "Hallway",
"notes": "Any devices present in the hallway",
"_pivot_device_id": 23,
"_pivot_group_id": 4
},
{
"id": 5,
"name": "Middle school",
"notes": "In classrooms 6-8",
"_pivot_device_id": 23,
"_pivot_group_id": 5
}
],
"mac": "123456789ABC"
},
{
"id": 26,
"name": "1:54PM July 5",
"airplayEnabled": false,
"airplayCodeEnabled": true,
"type": 0,
"groups": [
{
"id": 5,
"name": "Middle school",
"notes": "In classrooms 6-8",
"_pivot_device_id": 26,
"_pivot_group_id": 5
}
],
"mac": "123456789ABC"
}
]
I want to modify each returned item and remove the excess data, so it will end up like this:
[
{
"id": 23,
"name": "11:40AM July 2",
"airplayEnabled": false,
"airplayCodeEnabled": true,
"type": 0,
"groups": [4, 5],
"mac": "123456789ABC"
},
{
"id": 26,
"name": "1:54PM July 5",
"airplayEnabled": false,
"airplayCodeEnabled": true,
"type": 0,
"groups": [5],
"mac": "123456789ABC"
}
]
I created the following code to remove the excess data:
const deleteExcessInfo = async function(group) {
if(group.id) {
return group.id;
} else {
return null;
}
}
const modGroups = async function(device) {
async.map(device.groups, deleteExcessInfo, function(err, res) {
device.groups = res;
});
return device;
}
var newDevices;
async.map(devices, modGroups, (error, results) => {
console.log("results are " + JSON.stringify(results));
});
When I execute this code in a stand-alone node program (run from the command line), I get the expected output with the excess data removed. However, it does not work when I put it in a redux action, like this:
export function getDevices() {
return function(dispatch) {
return fetch("http://my-awesome-api:1357/device", {mode: "cors"})
.then(handleErrors)
.then(json)
.then(function(data) {
async.map(data, fixGroups, async function(error, res) {
console.log("dispatching...");
console.log(JSON.stringify(res));
dispatch({
type: "GET_DEVICES",
devices: res
});
});
}).catch((err) => {
dispatch({
type: "GET_DEVICES_ERROR",
error: err
});
alert("Oh shoot we have an error " + err);
return(err);
});
}
};
I do not see "dispatching..." or the res printed to the console, so it appears the callback function is not being executed for some reason. Any ideas on why it's not working, and on how to fix it? Thanks!
What I've tried
I tried implementing a promise as Moonjsit recommended, but it did not work. I have also tried implementing a promise in my Redux action, like this:
export function getDevices() {
return function(dispatch) {
return fetch("http://localhost:1357/device", {mode: "cors"})
.then(handleErrors)
.then(json)
.then(function(data) {
return new Promise((resolve, reject) => {
async.map(data, fixGroups, (error, results) => {
console.log("results are " + JSON.stringify(results));
resolve(dispatch({
type: "GET_DEVICES",
devices: results
});
});
});
}).catch((err) => {
dispatch({
type: "GET_DEVICES_ERROR",
error: err
});
alert("Oh shoot we have an error " + err);
return(err);
});
}
};
Either way, the code inside the callback does not execute.
Hey so you have a problem in your code.
const modGroups = async function(device) {
async.map(device.groups, deleteExcessInfo, function(err, res) {
device.groups = res;
});
return device;
}
Calling function above immediately starts async.map which is asynchronus, and then returns unchanged device variable. So effectively it gives same reults as:
const modGroups = async function(device) {
return device;
}
To fix it you can eg. wrap it in Promise:
const modGroups = async function(device) {
return new Promise((resolve, reject) => {
async.map(device.groups, deleteExcessInfo, function(err, res) {
if (err) {
reject(err);
} else {
device.groups = res;
resolve(device);
});
})
}

How to push named Json Array Into Json Object

I want to push below data. I want order the items, it consists of following fields:
var OrderItem = {"itemid":item.itemid,"itemname":item.itemname,"qty":1,"itemprice":item.itemprice};
But I want to Store Like this
{
"Items": [
{
"itemid": 50,
"itemname": "sample",
"itemprice": 124,
"qty": 1
},
{
"itemid": 52,
"itemname": "sample",
"itemprice": 124,
"qty": 1
}
]
}
Controllers:
$scope.addnew=function(item){
var OrderItem= {"itemid":item.itemid,"itemname":item.itemname,"qty":1,"itemprice":item.itemprice};
NewOrderService.addOrderitems(OrderItem);
}
}
Services:
servctrl.service("NewOrderService", function(NewOrderFactory) {
this.addOrderitems = function(orderitemnew) {
NewOrderFactory.AddOrdernew(orderitemnew);
}
});
Factorys:
factmodule.factory("NewOrderFactory",function(){
var orderitemsnew=[];
return {
AddOrdernew:function(orderitemnew){
orderitemsnew.push(orderitemnew);
}
}
});
How to Achieve this?
probably like this?
factmodule.factory("NewOrderFactory",function(){
var orderitemsnew={
items = [];
};
return{
AddOrdernew:function(orderitemnew){
orderitemsnew.items.push(orderitemnew);
},
getOrderItemsNewList: function() {
return orderitemsnew;
}
};
});

Resources