vue-autosuggest output object-object on twice click - javascript

by the way this question very similar on Vue algolia autosuggest on select showing [Object object]
but i still did not solve here is my debug or code
<b-form-group
label="Name Agen"
label-for="vi-agen-name"
>
<span v-text="form.agen.name_agen" />
<vue-autosuggest
id="vi-agen-name"
v-model="form.agen.name_agen"
:suggestions="[{ data: form.agen.agens }]"
:limit="7"
:input-props="{
id: 'autosuggest__input',
class: 'form-control',
placeholder: 'Name Agen',
}"
#selected="onSelectedFrom"
#input="searchForm($event, 'agen/', 'agen', 'name_agen')"
>
<template slot-scope="{suggestion}">
<span class="my-suggestion-item">{{ suggestion.item.name_agen }}</span>
</template>
</vue-autosuggest>
</b-form-group>
my problem:
i have on typing yogi on form input
select item that show on suggesstion : [ { data : [ { name_agen : 'Yogi' .....
<span v-text="form.agen.name_agen" /> // output : Yogi
form input // output : yogi
but when i tried to type again on form input yogiabc
thats not show any suggestion so i remove by backspace so the input now is yogi
then i tried select again
the unexpected on twice select :
<span v-text="form.agen.name_agen" /> // output : Yogi // why this result is string
form input // output : object-object // but on form input is an object-object ?
function code:
async onSelectedFrom(option) {
const model = this.form.currentModel
const fieldSuggest = this.form.currentFieldSuggest
const currentLoadData = this.form[`${model}`][`${model}s`]
const currentField = this.form[`${model}`][`${fieldSuggest}`]
this.form[`${model}`] = {
isNew: false,
[`${model}s`]: currentLoadData,
...option.item,
}
console.log('selected', this.form[`${model}`], 'Name Agen:', currentField)
},
searchForm(keyword, uri, model, currentSuggest) {
this.form.currentModel = model
this.form.currentFieldSuggest = currentSuggest
if (keyword) {
clearTimeout(this.timeoutDebounce)
this.timeoutDebounce = setTimeout(() => {
useJwt.http.get(`${uri}`, { params: { keyword, single_search: true } })
.then(response => {
// test debug
if (response.data.total_items === 0) {
// no data
this.form[`${model}`].isNew = true
this.form[`${model}`].user.full_name = null
this.form.isAgenAndTrans = false
this.form[`${model}`][`${model}s`] = []
console.log('no data show', this.form[`${model}`])
} else {
// this.form[`${model}`].isNew = false
this.form.isAgenAndTrans = false
this.form[`${model}`][`${model}s`] = response.data[`${model}s`]
}
}).catch(e => {
this.form[`${model}`].isNew = true
this.form[`${model}`].user.full_name = null
this.form.isAgenAndTrans = false
this.form[`${model}`][`${model}s`] = []
})
}, 300)
}
},
then these the data
data() {
return {
payload: [],
form: {
currentModel: '',
currentFieldSuggest: '',
isAgenAndTrans: false,
agen: {
isNew: true,
id: 0,
name_agen: '',
dm_personal_id: 0,
user: {
full_name: '',
},
agens: [],
},
}
}
}

Related

Vue.js How to clear the selected option in a dropdown?

I added a button inside my dropdown that needs to clear the selected city.
I added an event but it isn't clearing the selected option.
Could you please suggest me what am I doing wrong ? Thank you very much.
This is the button in my dropdown
methods: {
...mapActions({
fetchCitiesByName: "fetchCitiesByName",
fetchCityDetails: "fetchCityDetails",
}),
async onClientComboSelect({value, label})
{
this.cityId = value;
this.city = label;
this.option.city = label;
this.additionalSearchField = {cityId: this.option.cityId, label: this.option.city};
await this.fetchCityInfo({id: this.option.cityId, label: this.option.city});
},
noCitySelected()
{
this.option.cityId = null;
this.$emit('input', this.option.cityId);
this.$emit('on-button-action', item);
},
<!-- Select City -->
<div
class="select-form-field"
>
<label
for="city"
class="inline-3-columns"
>
<span class="title__field">City*</span>
<combo-select
id="city"
v-model="option.cityId"
api-location="fetchCitiesByName"
api-details-location="fetchCityDetails"
search-parameter="cityName"
:additional-search-fields="additionalSearchField"
:transformer="cityTransformer"
:button="{event: noCitySelected, text: 'No City', icon: 'minus'}"
:config="{
...comboConfig,
searchLabel: 'Search Cities',
}"
:button-event="noCitySelected"
class="input input__typeahead"
#on-select-item="onCityComboSelect"
/>
<input
v-model="option.cityId"
type="hidden"
name="cityId"
>
</label>
</div>
<!-- End -->
here is the dropdown combo-select that I need I need to use. Is it possible to clear
<script>
const COMBO_STATES = Object.freeze({
OPEN: "OPEN",
CLOSED: "CLOSED"
});
const LOADING_STATES = Object.freeze({
LOADING: "LOADING",
BLOCKED: "BLOCKED",
DEFAULT: "DEFAULT"
});
export default {
directives: {
clickOutside: vClickOutside.directive,
focus: {
inserted: (el) =>
{
el.focus();
}
}
},
components:
{
InfiniteScroll
},
model: {
prop: 'selectedId',
},
props:
{
apiLocation: {
type: String,
required: true,
default: ""
},
apiDetailsLocation: {
type: String,
required: false,
default: ""
},
transformer: {
type: Function,
required: true,
default: () => ([])
},
selectedId: {
type: Number|null,
required: false,
default: null
},
selectedItems: {
type: Array,
required: false,
default: () => ([])
},
searchParameter: {
type: String,
required: false,
default: "name"
},
// temporary as the form css is too much hassle to adjust
details: {
type: String|null,
required: false,
default: null
},
additionalSearchFields: {
type: Object,
required: false,
default: () => ({})
},
getter: {
type: String,
required: false,
default: ""
},
button: {
type: Object,
required: false,
default: null
},
config: {
type: Object,
required: true,
default: () => ({})
},
canSendDifferentValue: {
type: Boolean,
required: false,
default: true
}
},
data()
{
return {
searchable: "",
openState: COMBO_STATES.CLOSED,
itemsInitializationNotEmpty: false,
selectedItem: CSItem(),
items: [],
iterations: 0,
isLoading: false,
page: 0,
pagingLoadingState: LOADING_STATES.DEFAULT,
defaultConfig: {
itemsPerPage: 20,
numberOfItemsShown: 4,
searchLabel: "Search for more...",
showDefaultLabelOnSelect: false,
clearSelectedItems: false,
isEditable: true,
isImmediate: true
}
};
},
computed:
{
hasSubitemSlot()
{
return !!this.$slots.subitem || !!this.$scopedSlots.subitem;
},
isComboSelectEditable()
{
return this.innerConfig.isEditable;
},
isOpen()
{
return this.openState === COMBO_STATES.OPEN;
},
comboItems()
{
let items = this.items;
if(this.innerConfig.clearSelectedItems)
items = this.items.filter(({id}) => !this.selectedItems.includes(id));
return CSItemList(items, this.transformer);
},
comboSelectItem()
{
const defaultLabel = this.innerConfig.isEditable ? "Select" : "";
if(this.innerConfig.showDefaultLabelOnSelect) return defaultLabel;
if(this.selectedItem.value)
{
const {label = defaultLabel} = this.comboItems.find(({value}) => value === this.selectedItem.value) || {};
return label;
}
return this.selectedItem.label ? this.selectedItem.label : defaultLabel;
},
innerConfig()
{
return Object.assign({}, this.defaultConfig, this.config);
},
hasNoItems()
{
return this.filterItems(this.items).length === 0;
},
skip()
{
return this.innerConfig.itemsPerPage * this.page;
},
isPagingLoading()
{
return this.pagingLoadingState === LOADING_STATES.LOADING;
},
isPagingLoadingBlocked()
{
return this.pagingLoadingState === LOADING_STATES.BLOCKED;
}
},
watch:
{
additionalSearchFields:
{
deep: true,
handler(newValue, oldValue)
{
if(newValue && !isEqual(newValue, oldValue))
this.getItems(false);
}
},
selectedId: function(newValue, oldValue)
{
if(newValue === oldValue) return;
this.findSelectedItem();
},
items: function(newValue, oldValue)
{
const allItems = this.filterItems(newValue);
if (allItems.length === 0 && oldValue.length !== 0) return;
if (allItems.length === 0 && oldValue.length === 0 && this.itemsInitializationNotEmpty) return;
if(allItems.length === 0)
this.$emit("on-no-items");
this.itemsInitializationNotEmpty = true;
}
},
async mounted()
{
try
{
if(!this.innerConfig.isImmediate) return;
const initialSearchParams = this.searchable.length > 0 ? {[this.searchParameter]: this.searchable} : {};
this.items = await this.$store.dispatch(this.apiLocation, Object.assign({
top: this.innerConfig.itemsPerPage,
load: false,
skip: this.page,
...initialSearchParams
}, this.additionalSearchFields
));
this.findSelectedItem();
this.searchValue$ = "";
this.requestSubscription = requestSourceService
.getInstance()
.search
.subscribe(search =>
{
const {source, value} = search;
if(this.searchValue$ === value)
Reflect.apply(source.cancel, null, [
"Cancel previous request"
]);
this.searchValue$ = value;
});
}
catch(error)
{
this.errorHandler();
}
},
destroyed()
{
if(this.requestSubscription)
this.requestSubscription.unsubscribe();
},
methods:
{
errorHandler()
{
this.isLoading = false;
this.items = [];
},
search: debounce(async function()
{
if(this.searchable.length > 0 && this.searchable.length < 2) return;
this.isLoading = true;
await this.getItems(false);
}, 300),
async getItems(isCancelable = true)
{
try
{
this.page = 0;
this.items = await this.$store.dispatch(this.apiLocation, Object.assign({
top: this.innerConfig.itemsPerPage,
load: false,
skip: this.skip,
[this.searchParameter]: this.searchable ? this.searchable : null,
cancelable: isCancelable,
isThrowable: true,
}, this.additionalSearchFields));
this.isLoading = false;
const allItems = this.filterItems(this.items);
if(allItems.length === 0)
this.$emit("on-no-items");
this.pagingLoadingState = LOADING_STATES.DEFAULT;
this.findSelectedItem();
}
catch(error)
{
this.errorHandler(error);
}
},
async findSelectedItem()
{
if(!this.selectedId) return;
const item = this.comboItems.find(item => item.value === this.selectedId);
if(item)
{
const selectedItem = CSItem({
value: this.selectedId,
label: item ? item.label : null,
...item
});
this.selectedItem = selectedItem;
this.iterations = 0;
}
else
{
{
if(!this.apiDetailsLocation) return;
if(this.iterations === 1) return;
const itemDetails = await this.$store.dispatch(this.apiDetailsLocation, {
id: this.selectedId,
isThrowable: true
});
this.items.push(itemDetails);
this.iterations = 1;
await this.findSelectedItem();
}
catch (error)
{
console.error(error);
}
}
},
selectItem(item)
{
this.selectedItem = item;
// check if it should be sent
if(this.canSendDifferentValue)
this.$emit('input', item.value);
this.$emit('on-select-item', item);
this.close();
},
async onScrollEnd()
{
if(this.isPagingLoading || this.isPagingLoadingBlocked || (this.searchable.length > 0 && this.searchable.length < 2)) return;
try
{
this.pagingLoadingState = LOADING_STATES.LOADING;
this.page++;
const items = await this.$store.dispatch(this.apiLocation, Object.assign({
top: this.innerConfig.itemsPerPage,
load: false,
skip: this.skip,
[this.searchParameter]: this.searchable ? this.searchable : null,
isThrowable: true,
}, this.additionalSearchFields));
if(items.length === 0)
{
this.pagingLoadingState = LOADING_STATES.BLOCKED;
return;
}
this.items = this.items.concat(items);
const allItems = this.filterItems(this.items);
if(allItems.length === 0)
{
this.$emit("on-no-items");
}
this.pagingLoadingState = LOADING_STATES.DEFAULT;
}
catch(error)
{
console.error(error);
this.errorHandler(error);
this.pagingLoadingState = LOADING_STATES.DEFAULT;
}
},
filterItems(items)
{
return this.innerConfig.itemsFilter ? this.innerConfig.itemsFilter(items) : items;
},
dispatch(action)
{
this.$emit("on-button-action", action);
},
toggleComboOpenState()
{
if(!this.innerConfig.isEditable) return;
return this.openState = this.isOpen ? COMBO_STATES.CLOSED : COMBO_STATES.OPEN;
},
close()
{
this.openState = COMBO_STATES.CLOSED;
}
}
};
</script>
<template>
<div>
<div
v-click-outside="close"
:class="['combo-select', { 'combo-select__disabled': !isComboSelectEditable }]"
#click="toggleComboOpenState"
>
<span class="combo-select__selecteditem">
<span
v-if="comboSelectItem === 'Select'"
id="selected-item"
>{{ comboSelectItem }}</span>
<span
v-else
id="selected-item"
v-tippy="{ placement : 'bottom', content: comboSelectItem, }"
>{{ comboSelectItem }}</span>
</span>
<font-awesome-icon
icon="caret-down"
class="dropdown--arrow f-22"
/>
<transition
name="slidedown"
appear
>
<div
v-if="isOpen"
class="sub-menu"
>
<section class="sub-search input input__typeahead field">
<div class="input-group">
<input
v-model="searchable"
v-focus
type="text"
:placeholder="innerConfig.searchLabel"
#click.stop=""
#input="search"
>
<div class="input-group-append">
<font-awesome-icon
v-if="!isLoading"
icon="search"
class="typeahead-icon"
/>
<font-awesome-icon
v-if="isLoading"
icon="spinner"
class="fa-spin relative f-25 cl-body"
/>
</div>
</div>
</section>
<infinite-scroll
v-if="!hasSubitemSlot"
:button="button"
:is-loading="isPagingLoading"
#scroll-end="onScrollEnd"
>
<template #list>
<h2
v-for="(item, index) in comboItems"
:key="`${item.label}-${index}`"
v-tippy="{
placement : 'bottom',
content: item.label,
}"
:class="['sub-menu__item', {'selected': selectedItem.value === item.value}]"
#click.stop="selectItem(item)"
>
{{ item.label }}
</h2>
<h2
v-if="hasNoItems"
class="sub-menu__item pointer-events-none"
>
No items
</h2>
</template>
</infinite-scroll>
<infinite-scroll
v-if="hasSubitemSlot"
:button="button"
:is-loading="isPagingLoading"
#scroll-end="onScrollEnd"
>
<template #list>
<div
v-for="(item, index) in comboItems"
:key="`${item.label}-${index}`"
>
<slot
name="subitem"
:index="index"
:item="item"
:isSelected="selectedItem.value === item.value"
:close="close"
:action="selectItem"
/>
<h2
v-if="hasNoItems"
class="sub-menu__item pointer-events-none"
>
No items
</h2>
</div>
</template>
</infinite-scroll>
<section
v-if="button"
class="sub-button"
>
<button
class="btn btn--creation btn--creation--grey btn--creation--square w-100 h-100 br-r-0"
#click="dispatch(button.action)"
>
<font-awesome-icon :icon="button.icon" />
<span>{{ button.text }}</span>
</button>
</section>
<!-- this should be shown only on infinite loading -->
</div>
</transition>
</div>
<span
v-if="details"
class="flex w-mc f-11 cl-6f-grey p-l-10 p-t-3"
>({{ details }})</span>
</div>
</template>
You should show your UI component library name, because combo-select would have its own usage.
Maybe you can install vue-devtools to inspect data or other bugs in your development environment.

default value of autocomplete with vuetify

so i make an signup and address form for every user and i want every time the user is connected and navigate to the profile page, he will edit his details.
now i have async autocomplete from api that get for me all the items in object format,
so i tried to give the v-model an default value but it didn't change, i guess there is supposed to be connection between the items to the v-model, so i tried to fake the async search and get the items but still couldn't see the default value.
i don't care if the value wont be in the data i just want to see it visual
<script>
export default {
props: {
cmd: {
type: String
},
itemText: {
type: String
},
itemValue: {
type: String
},
label: {
type: String
},
city: {
type: Number
},
street: {
type: Number
},
type: {
type: String
},
defaultValue: {
type: String || Number
}
},
data() {
return {
loading: false,
items: [],
search: null,
select: null
};
},
watch: {
search(val) {
val && val !== this.select && this.querySelections(val);
},
select(val) {
if (val !== this.defaultValue) {
this.$emit("selected", { value: val[this.itemValue], text: val[this.itemText] });
}
}
},
async mounted() {
const defaultSelected = {};
defaultSelected[`${this.itemText}`] = this.defaultValue ? this.defaultValue.value : this.defaultValue;
defaultSelected[`${this.itemValue}`] = this.defaultValue ? this.defaultValue.id : this.defaultValue;
await this.querySelections(defaultSelected[`${this.itemText}`]);
console.log(this.items);
// this.select = defaultSelected[`${this.itemText}`];
},
methods: {
async querySelections(v) {
this.loading = true;
// Simulated ajax query
const data = (await this.$services.SearchService.searchAddress(v, this.cmd, this.city, this.street)).data;
console.log(data);
if (this.type === "city") {
this.items = data.Data[`CitiesRes`];
}
if (this.type === "street") {
this.items = data.Data[`StreetsRes`];
}
if (this.type === "streetNumber") {
this.items = data.Data["NumbersRes"];
}
this.loading = false;
},
asyncinsertDefualtData() {}
}
};
</script>
<template>
<v-autocomplete
v-model="select"
:loading="loading"
:items="items"
:search-input.sync="search"
:item-text="itemText"
:item-value="itemValue"
:value="defaultValue"
return-object
cache-items
flat
hide-no-data
hide-details
solo
:label="label"
></v-autocomplete>
</template>

How can i clear the chat input-box after sending the message(from suggestion) in botframework webchat?

i'm working on a bot application using react js and botframework webchat. The thing is that i want to clear the text input box (from where msgs are sent) after sending the message - which is selected from the suggestion. The Suggestion list(or autocomplete component) is a custom coded one. And What i mean is that if i type "hr" the suggestion list popup will come and if i click on one option from the suggestion, say 'hr portal', it will be sent, but what i wrote ie "hr" remains there in the input field and i want to clear that. And please note that If i type something and send its working fine. The problem is only when i type something and select something from the suggestion. Everything else is fine. How can i clear that. Any help would be really appreciated.
please find the below image for more understanding.
here's my code;
import React from 'react';
import { DirectLine, ConnectionStatus } from 'botframework-directlinejs';
import ReactWebChat from 'botframework-webchat';
import './ChatComponent.css';
var val;
var apiParameters = [];
var currentFocus = -1;
export default class extends React.Component {
constructor(props) {
super(props);
this.state = {
token: '',
conversationId: '',
directLine: {},
view: false,
feedBack: null,
value: '',
popupContent: '',
storeValue: '',
suggestions: [],
suggestionCallback: '',
suggestionTypedText: "",
typingChecking: "false",
};
this.handleTokenGeneration = this.handleTokenGeneration.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSaveFeedback = this.handleSaveFeedback.bind(this);
this.handleSuggestion = this.handleSuggestion.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleSuggestionClick = this.handleSuggestionClick.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.moveHighlight = this.moveHighlight.bind(this);
this.getSuggestionHtml = this.getSuggestionHtml.bind(this);
}
getSuggestionHtml(suggestion) {
const lowerCaseSuggestion = suggestion.toLowerCase();
return {
__html: lowerCaseSuggestion.includes(this.state.suggestionTypedText) ? lowerCaseSuggestion
.replace(this.state.suggestionTypedText, `<b>${this.state.suggestionTypedText}</b>`) : lowerCaseSuggestion
};
}
handleTokenGeneration = async () => {
console.log("11111");
const response = await fetch(`api/TokenGenerationService/GetToken`);
const data = await response.json();
this.setState({
token: data.categoryObject.token, conversationId:
data.categoryObject.conversationId
});
this.state.directLine = new DirectLine({ token: this.state.token });
this.setState({ view: true });
this.setState({ typingChecking: "true" });
console.log("conversationId");
};
async handleSuggestion(val, store) {
if (val === "") {
this.setState({
suggestions: []
});
}
else {
apiParameters = [];
var valuess = null;
const response = await fetch(`api/TokenGenerationService/GetAzureSearch?myparam1=${val}`);
const data = await response.json();
var values = ["Hello", "yes", "no", "exit", "Welcome", "Thank You", "Approve", "Apply leave", "Reject", "Absence Balance", "Leave Balance", "Upcoming Holidays", "Apply Comp-Off", "Approve Leave", "Raise Incident Tickets", "Project Allocation Info", "Reporting Manager Change", "Reporting Manager Approval", "Approve Isolve Tickets", "My Manager", "My Account Manager", "Generate Salary Certificate", "Isolve Ticket Status", "Internal Job Posting", "My Designation", "My Joining Date", "RM Approval", "RM Change", "Resource Allocation", "ESettlement Approval", "SO Approval", "Cash advance Approval", "Purchase Request Approval", "Referral status", "HR Ticket", "Platinum Support"];
valuess = values.filter(s =>
s.toLocaleLowerCase().startsWith(val.toLowerCase())
);
valuess = valuess.concat(data.az_search);
this.setState({
suggestions: valuess,
suggestionCallback: store,
suggestionTypedText: val.toLowerCase()
});
// alert(data.az_search);
var totCount = data.az_search;
console.log("kkkkkk" + totCount);
}
}
moveHighlight(event, direction) {
event.preventDefault();
const { highlightedIndex, suggestions } = this.state;
if (!suggestions.length) return;
let newIndex = (highlightedIndex + direction + suggestions.length) % suggestions.length;
if (newIndex !== highlightedIndex) {
this.setState({
highlightedIndex: newIndex,
});
}
}
keyDownHandlers = {
ArrowDown(event) {
this.moveHighlight(event, 1);
},
ArrowUp(event) {
this.moveHighlight(event, -1);
},
Enter(event) {
const { suggestions } = this.state;
if (!suggestions.length) {
// menu is closed so there is no selection to accept -> do nothing
return
}
event.preventDefault()
this.applySuggestion(suggestions[this.state.highlightedIndex]);
},
}
handleKeyDown(event) {
// console.log("lokkkkkkkkkkkk")
if (this.keyDownHandlers[event.key])
this.keyDownHandlers[event.key].call(this, event)
}
async handleSuggestionClick(event) {
await this.applySuggestion(event.currentTarget.textContent);
}
async applySuggestion(newValue) {
//newValue = null;
await this.setState({ typingChecking: "false", suggestions: [], highlightedIndex: 0 });
this.state.suggestionCallback.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: {
text: newValue
}
});
await this.setState({ typingChecking: "true" });
}
getSuggestionCss(index) {
var HIGHLIGHTED_CSS = "HIGHLIGHTED_CSS";
var SUGGESTION_CSS = "SUGGESTION_CSS";
return index === this.state.highlightedIndex ? HIGHLIGHTED_CSS : SUGGESTION_CSS;
}
handleClose(elmnt) {
var x = document.getElementsByClassName("autocomplete-items");
for (var i = 0; i < x.length; i++) {
if (elmnt !== x[i]) {
x[i].parentNode.removeChild(x[i]);
}
}
}
async componentDidMount() {
try {
await this.handleTokenGeneration();
const store =
window.WebChat.createStore(
{},
({ getState }) => next => action => {
this.state.directLine.connectionStatus$
.subscribe(connectionStatus => {
if (connectionStatus === ConnectionStatus.ExpiredToken) {
console.log("expired");
}
if (action.type === 'WEB_CHAT/SET_SEND_BOX') {
const val = action.payload.text;
if (this.state.typingChecking === "true") {
this.setState({
highlightedIndex: -1,
});
console.log(this.state.typingChecking);
this.handleSuggestion(val, store);
}
}
if (action.type === 'DIRECT_LINE/DISCONNECT_FULFILLED') {
console.log("final" + connectionStatus);
console.log("finalexpired" + ConnectionStatus.ExpiredToken);
console.log("final");
this.handleTokenGeneration();
}
});
return next(action)
}
);
this.setState({ storeValue: store });
} catch (error) {
console.log("error in fetching token");
console.log(error);
}
this.state.directLine.activity$
.filter(activity => activity.type === 'message')
.subscribe(function (activity) {
//console.log("oooooooooooooooooooooo");
}
// message => console.log("received message ", message.text)
);
}
handleSaveFeedback(ans) {
// console.log(this.state.conversationId);
// console.log(this.state.feedBack);
var userID = "C94570";
var feedbackmsg = this.state.value;
var feedbacktype = this.state.feedBack;
var convId = this.state.conversationId;
fetch('api/Feedback/SaveFeedback',
{
method: "POST",
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ Uid: userID, FeedbackMessage: feedbackmsg, Convid: convId, FeedbackType: feedbacktype })
}).
then(response => response.text())
.then(data => {
console.log(data.getResult);
});
this.setState({ value: '' });
}
feedback(ans) {
this.setState({ feedBack: ans });
if (ans === "Send") {
this.handleSaveFeedback(ans);
}
else if (ans === "Yes") {
this.setState({ popupContent: "How was your experience?" });
// console.log(this.state.value)
}
else if (ans === "No") {
this.setState({ popupContent: "What went wrong?" });
// console.log(this.state.value)
}
}
handleChange = (event) => {
this.setState({ value: event.target.value });
}
styleOptions = {
bubbleBackground: 'rgba(0, 0, 255, .1)',
bubbleFromUserBackground: 'rgba(0, 255, 0, .1)',
botAvatarInitials: 'DIA',
userAvatarInitials: 'ME'
}
render() {
if (!this.state.view) {
return
<div />
} else {
const filteredSuggestions = this.state.suggestions.filter(
suggestion =>
suggestion.toLowerCase().indexOf(this.state.suggestionTypedText.toLowerCase())
> -1
);
// console.log(this.state.view);
return (
<div className="react-container webchat" >
<div onKeyDown={this.handleKeyDown.bind(this)}>
<div >
<ReactWebChat styleOptions={this.styleOptions} directLine={this.state.directLine} webSocket={true} userID='C94570' username='Thomas' store={this.state.storeValue} sendTypingIndicator={true} />
</div>
</div>
<div className="SuggestionParent" id="Suggestion1">
{this.state.suggestions.map((suggestion, index) => (
<div className={this.getSuggestionCss(index)} key={index} onClick={this.handleSuggestionClick} >
{suggestion
.toLowerCase()
.startsWith(this.state.suggestionTypedText) ? (
<div>
<b>{this.state.suggestionTypedText}</b>
{suggestion
.toLowerCase()
.replace(this.state.suggestionTypedText, "")}
</div>
) : (
<div dangerouslySetInnerHTML={this.getSuggestionHtml(suggestion)} />
)}
</div>
))}
</div>
<footer className="chat-footer" >
<div className="foot-footer">
Was I helpful ?
<span className="feedback" onClick={() => this.feedback("Yes")} >Yes</span><span>|</span><span className="feedback" onClick={() => this.feedback("No")}>No</span>
{
this.state.feedBack === "Yes" || this.state.feedBack === "No" ?
(
<div className="dialog" id="myform">
<div id="textfeedback">
<span id="closeFeedback" onClick={() => this.feedback("Close")}>X</span>
<p>{this.state.popupContent}</p>
<input type="text" id="feedbacktxtbox" required name="textfeedback" placeholder="Pleasure to hear from u!"
onChange={this.handleChange}
value={this.state.value} />
<button type="button" id="btnfeedback" onClick={() => this.feedback("Send")}>send</button>
</div>
</div>
) : null
}
</div>
</footer>
</div>
);
}
}
}
The chat input box is called the send box in Web Chat. Clearing the send box is just setting the send box with an empty string. This is done automatically when you click on the send button normally. You can see in the submit send box saga that submitting the send box means performing two actions: sending the message and setting the send box.
if (sendBoxValue) {
yield put(sendMessage(sendBoxValue.trim(), method, { channelData }));
yield put(setSendBox(''));
}
This means that if you use the SUBMIT_SEND_BOX action then the send box will be cleared automatically. Of course, if you want that to work with your autocomplete component then you'll need to set the send box with the autocompleted text before you submit it. Your other option is to just use the SET_SEND_BOX action with an empty string after you send the message.

Error : Cannot read property 'name' of undefined?

this is a part code file app.js
....
this.state = {
todoList: [
{ id: 1, name: "Khoa" },
{ id: 2, name: "Linh" },
{ id: 3, name: "Luc" },
],
inputText: "",
currentName: "",
todoSearch : []
};
}
....
handleSubmit = (e, inputRef) => {
const { todoList, currentName } = this.state;
if (inputRef.current.value.trim() === "")
alert("Hay nhap du lieu can input");
else {
if (currentName !== "") {
this.setState({
todoList : todoList.map(item => {
if(item.name === currentName) {
return {...item, name : inputRef.current.value}// error this code
}
}),
currentName : ''
})
} else {
const data = { id: todoList.length + 1, name: inputRef.current.value };
console.log("say hi");
this.setState({
todoList: [...todoList, data],
currentName : ''
});
}
}
};
.....
I want to update data unsatisfactorily item.name === currentName . Meaning replace name old of object in todoList equal new name is inputRef.current.value but not work. help me
Put else if the value doesn't match -
todoList : todoList.map(item => {
if(item.name === currentName) {
return {...item, name : inputRef.current.value}// error this code
}else{
return {...item}
})

React json schema form relations

From the step 1 dropdown if the user is picking one after submit redirect it to step2schema, and if he is picking two redirect him after submit to step3schema. Here is the jsfiddle (check my link):
const Form = JSONSchemaForm.default;
const step1schema = {
title: "Step 1",
type: "number",
enum: [1, 2],
enumNames: ["one", "two"]
};
const step2schema = {
title: "Step 2",
type: "object",
required: ["age"],
properties: {
age: {type: "integer"}
}
};
const step3schema = {
title: "Step 3",
type: "object",
required: ["number"],
properties: {
number: {type: "integer"}
}
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {step: 1, formData: {}};
}
onSubmit = ({formData}) => {
if (this.state.step === 1) {
this.setState({
step: 2,
formData: {
...this.state.formData,
...formData
},
});
} else {
alert("You submitted " + JSON.stringify(formData, null, 2));
}
}
render() {
return (
<Form
schema={this.state.step === 1 ? step1schema : step2schema}
onSubmit={this.onSubmit}
formData={this.state.formData}/>
);
}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://npmcdn.com/react-jsonschema-form#1.0.0/dist/react-jsonschema-form.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
https://jsfiddle.net/bogdanul11/sn4bnw9h/29/
Here is the lib I used for documentation: https://github.com/mozilla-services/react-jsonschema-form
What I need to change in order to have my desired behavoir ?
Replace your state to this first
this.state = {step: 0, formData: {}};
Then replace your onSubmit logic to
onSubmit = ({formData}) => {
const submitted = formData;
this.setState({
step: submitted,
formData: {
...this.state.formData,
...formData
},
})
}
Finally replace your schema logic
schema={this.state.step === 0 ? step1schema : ( this.state.step === 1 ? step2schema : step3schema)}
the schema selecting ternary operation is what we call a compound ternary operation. If state.step is 0 , we select step1schema... if not a new selection statement ( this.state.step === 1 ? step2schema : step3schema) is run; in which if step is 1, step2schema is selected and for anything else step3schema.
Lets say you have more than 3 schemas and you want to access them. For that you will have to define the schemas in an array and access them using the index.
schemaArray = [ {
// schema1 here
} , {
// schema2 here
} , {
// schema3 here
}, {
// schema4 here
}, {
....
}]
Now your schema selecting you will have to use
schema = { schemaArray[ this.state.step ] }

Categories

Resources