From a Microsoft Teams bot I send an Adaptive Card with input fields and a Submit action. When the user clicks Submit I receive the data entered but the form fields are cleared.
Why is this? What am I doing wrong? This behavior is extremely annoying as I can't verify the input and ask the user to correct it.
This happens in the desktop Teams app, Teams in a browser, Teams webchat in a web page and the Bot Emulator. In the Emulator it suffices for the field to loose focus.
In case it matters I use nodejs.
You're not doing anything wrong. That's just how Adaptive Cards work in Teams, perhaps as a way to signify that the data has been sent to the bot successfully. There may be something you can do to fix your problem though.
Adaptive Card input fields have a value property that allows you to specify the field's initial value. If you send a card to the user and the input fields' value properties are populated, the fields won't be empty. This means you can send such a card as an update instead of a new activity and it will look like the card has been modified in place, since Teams supports updating activities. If the update uses the same card but with the values the user entered then it will look like the card remains unchanged, which would fix your problem of the values disappearing.
There was a question about dynamically adding input fields to Adaptive Cards, and the answer contains sample code that preserves input field values:
var inputId = `text${i}`;
body.push({
type: "Input.Text",
id: inputId,
value: cardData[inputId] // This is where the value is preserved
});
If you want this whole process to be made easier with prebuilt code that you can install in NuGet packages, feel free to voice your support for these ideas on GitHub:
Bot.Builder.Community.AdaptiveCards
AdaptiveCard Prompt
While I was waiting for an answer to my question I came pretty much to the same conclusion as Kyle Delaney outlined above, you have to resend the data entered.
So I started to fiddle with my code and came up with this solution, not sure this is the best way.
As part of a waterfall step:
async W2_showCard(step) {
const card = CardFactory.adaptiveCard(this.makeFormCard());
return await step.prompt('formPrompt', { prompt: MessageFactory.attachment(card) });
}
The trick is in formPrompt which also ensures the user submits the form instead of doing something else.
// Workaround to make user click Submit or cancel dialog
this.dialogs.add(new ActivityPrompt('formPrompt', async prompt => {
const recognizedValue = prompt.recognized.value;
if (recognizedValue.type === ActivityTypes.Message) {
if (recognizedValue.value) {
const replyToId = recognizedValue.replyToId;
var oldCard = prompt.options.prompt.attachments[0];
var validated = true;
oldCard.content.body.forEach((item, i, body) => {
if (item.type === "Input.Text" || item.type === "Input.ChoiceSet") {
// preserve the user input
const newValue = recognizedValue.value[item.id];
item.value = newValue;
// some rudimentary input validation:
// assumes there is a corresponding text field just
// prior to the input field (input fields
// can't change their color)
if (newValue == '') {
body[i - 1].color = 'Attention';
body[i - 1].weight = 'Bolder';
validated = false;
} else {
delete body[i - 1].color;
delete body[i - 1].weight;
}
}
});
if( validated ) {
// remove the submit and cancel actions (not required, debatable)
delete oldCard.content.actions;
}
// update the card
const activity = prompt.context.activity;
activity.attachments = [oldCard];
activity.id = replyToId;
await prompt.context.updateActivity(activity);
if (validated) {
// this is to make input available in next waterfall step
prompt.recognized.value = recognizedValue.value;
return true;
} else {
await prompt.context.sendActivity(`Please check the form. Some values are missing`);
}
} else {
await prompt.context.sendActivity(`Please fill out form and press *"submit"* button or type *"cancel"* to stop.`);
}
}
return false;
}));
Related
I have a text input field in an electron-react app. The windows.alert() was being used to through an alert on altering a state given a certain condition. But after throwing the alert, an input text field in a completely separate form would not allow the user to enter data without clicking out of the application and then back in.
I do currently have a work around, which was throwing the alert using electron's ipcRenderer and ipcMain, but the style does not match well with the rest of the application. Is there a way to handle windows.alert() that does not block data entry into text input fields? What causes windows.alert() to block entering data into text input?
Code Example Before:
function doSomething(value) {
let array = otherArray;
if (array.length == 0) {
//The below was blocking typing into <input> in a completely separate form.
window.alert("Please add expected value first")
}
}
Work around code with ipcRenderer from preload.js and ipcMain:
function doSomething(value) {
let array = otherArray;
if (array.length == 0) {
window.api.send("send-alert", "Please add expected value first")
}
}
//in main.js
ipcMain.on("send-alert", (event, incomingMessage)=> {
let options = {
message: incomingMessage
}
dialog.showMessageBox(mainBrowserWindow, options)
}
Use toastr to walk around this.
Read this: https://github.com/CodeSeven/toastr
Trigger an error or warning message in place of the window.alert() method. Ie:
toastr.warning() or toastr.error()
I have a problem regarding form validation with vuelidate. I’m using Vue 2.9.6 with vuelidate 0.7.5
I recommend opening this jsfiddle while reading my problem description:
jsfiddle.net/Philgarth/h5v7km2s/
(SO prevents me from posting the link properly, sorry .... just prepend "https://")
I’m developing an account book for private bank accounts and currently I’m working on the depositor-form-component, where users can add new depositors. Each depositor must have a name and at least one bank account to submit the depositor-form and return to the account-view-component.
As you can see in the jsfiddle I have a textfield for the name and a dropdown for the accounts which initially is empty and disabled. A new account can be drafted by clicking the „+“-button besides the dropdown. With „drafted“ I mean, that the account in the finished app shouldn’t get posted to the database right away. Because users should be able to create multiple accounts for a depositor only the finished and validated depositor-object with one ore more accounts is sent to the database by submitting the whole depositor-form.
While a new account is drafted, the variable „pendingAccountCreation“ is set to true, which is why the account fields are displayed via „v-if“ as well as two buttons to submit or discard the account data.
When clicking on either of these buttons, the validation-object „updatedAccount“ should be resetted, so that by drafting another account the fields neither are dirty nor have errors.
Now the problem is, that the validators don’t react to changes to the input field in some cases – e.g. „required“ remains false although the input field is not empty.
I made some tests and could determine that the error only occurs, when an account-draft is discarded by clicking the „x“-button while no other accounts are already created. As soon as at least one account is created and available in the dropdown everything works as expected and the validators react to input changes when drafting another account.
Now if you want to help me I ask you to reproduce the error in the jsfiddle and try to figure out, what I’m doing wrong here.
Thanks in advance and have a nice day 😊
Change this code:
discardAccountDraft(accountValidator) {
accountValidator.$reset();
this.selectedAccountIndex = 0;
if (this.updatedDepositor.accounts.length !== 0) {
this.selectedAccount = this.updatedDepositor.accounts[0];
this.updatedAccount = this.cloneObject(this.selectedAccount);
} else {
this.updatedAccount = this.cloneObjectModel;
}
this.pendingAccountCreation = false;
},
to this code (jsfiddle):
discardAccountDraft(accountValidator) {
accountValidator.$reset();
this.selectedAccountIndex = 0;
if (this.updatedDepositor.accounts.length !== 0) {
this.selectedAccount = this.updatedDepositor.accounts[0];
this.updatedAccount = this.cloneObject(this.selectedAccount);
} else {
this.updatedAccount = this.cloneObjectModel({
id: "",
accountNumber: "",
iban: "",
bic: "",
accountDescription: "",
});
}
this.pendingAccountCreation = false;
},
I've just added empty model to your cloneObjectModel function, because it expects one... And this fixed the problem you mentioned:
error only occurs, when an account-draft is discarded by clicking the „x“-button while no other accounts are already created
I'm writing a diary app in React for a uni project, please appreciate that I cannot upload much code as the school has strict plagiarism rules and runs checks etc...
I'll explain the problem in points:
User enters diary entry in the textarea
If they click the save button or anywhere outside the texarea, the text is saved
Text is saved by firing redux action that makes an axios request to the node server where the journal is updated
A redux reducer sets the new state of the journal and now I can access the journal entries using journal.data.entries
I now have a displayEntry function that checks the date of the entry, and loads the entry content into the matching date in the journal. This works fine and correct data is loaded on the right day
PROBLEM - I am setting the textarea value attribute to the return value of this function i.e. the entry.content if it exists or "" if it doesn't. When value is set on the textarea I can't type into it anymore to update the content for that day or add a new entry to another day. Removing the value property allows me to type into it again
displayEntry() function:
displayEntry() {
const { todaysDate } = this.state;
const { journal } = this.props;
if (journal) {
for (let entry of journal.data.entries) {
if (entry.date === todaysDate) {
return entry.content;
}
}
return "";
}
return "";
}
All help appreciated. If more info is required I'll do my best to provide it
I have requirement in one of my projects where users would like to see a message before they leave the page or close the browser/window if the form data has been changed. I found this function that will catch the scenario if user is leaving the window or closing the browser.
window.addEventListener('beforeunload', function (e) {
e.preventDefault();
e.returnValue = '';
});
I'm wondering if there is a way to show that message only if form data has been changed. SO user in that case would know that data has changed. I did not find a lot about this topic or any constructive solutions so far. If anyone have any examples or suggestions please let me know.
Thank you.
If you're not using any modern framework you can build your custom Form State helper.
When form is ready on DOM you can iterate over each input element and assign a data property say (data-init-val) and set its value equal to the input element value.
let inputs = document.querySelectorAll('form#userform input');
for(let inputEl of inputs){
inputEl.setAttribute('oldVal', inputEl.value);
}
This way you're caching the existing form values. When user is closing the window you can run a function to compare current input values with the initial cached values via:
function checkFormState(){
let inputs = document.querySelectorAll('form#userform input');
let stateChanged = false;
for(let inputEl of inputs){
if(inputEl.getAttribute('oldVal') !== inputEl.value){
stateChanged = true;
break;
}
}
return stateChanged;
}
Your eventListener can make an informed decision based on the stateChanged value.
PS: You should modify the input element value caching/compare logic based on the input elements in your form.
Headover to https://jsfiddle.net/v9rztay6/ and see it in action.
I am attempting to show a certain class if a user clicked the right answer or wrong answer through the {{checkAnswer}} helper below:
<div class="question" {{attributes}}>
A
{{answerOne}}
</div>
A user submits an answer which creates a submission, and then ultimately that user submission is checked to see if it is correct. If the user submission is correct it should display btn-success, incorrect should be btn-danger, and else should be btn-primary.
Template.questionItem.helpers({
checkAnswer: function() {
var user = Meteor.user();
var game = GameCollection.findOne({current: true});
var currentQuestion = game.currentQuestion;
var question = game.gameQuestions[currentQuestion];
var correctAnswer = question.correctAnswer;
var submission = Submissions.findOne({userId: user._id,
gameId: game && game._id,
currentQuestion: currentQuestion});
if (submission && submission.submission === correctAnswer) {
return 'btn-success';
} else if (submission) {
return 'btn-danger';
} else {
return 'btn-primary upvotable'
}
},
When I click a correct submission it turns green from btn-success for a fraction of a second (and if incorrect it turns red for a fraction of a second) but then ultimately goes to btn primary. Why does it not stay btn-success (or btn-danger)?
Something in the context is changing. Meteor data contexts are built in such a way that all the 'current' checking you're doing isn't necessary. You can instead access the current data context using this, which will significantly simplify your code.
I'd start by checking if the submission is correct or not on the server side, and then storing that as a property of the submission itself. Then, you can do a simple if...then to return the correct bootstrap class name.
Here's a simple example: meteorpad
And if you want the JS files to quickly put into a brand new project, here's a Gist.
You'll notice in both of those how you can use this._id or this.correct to access the correct/current data context. Hope that helps / gets you on the right track.