select2 not selecting with no errors in the console - javascript

The dropdown list renders properly but when clicked on a dropdown result, nothing happens. I know that select2 expects the results to be in a certain way but couldn't figure out why the results won;t get selected when clicked on the result in the dropdown. No errors or anything in the console..
The response from the REST service is an array of objects with Person details.
Here's a jsfiddle that I have setup to illustrate the problem: https://jsfiddle.net/qygpb1Lr/
const $select2 = this.$element.find((`[rel='${this._interestedPartySelect2_id}']`));
const formatResult = person => {
if (!person || !person.FULL_NAME) return '';
return `
<strong>${person.LAST_NAME}, ${person.FIRST_NAME}</strong>
<br />
<i class='txt-color-cernerPurple'>${person.JOBTITLE || '--'}</i>
<br />
<span style="color:#525564">${person.DEPARTMENT || '--'}</span>
<br />
<span class='text-muted'>${person.INTERNET_E_MAIL || '--'}</span>
`;
};
const formatSelection = person => {
if (!person || !person.LAST_NAME || !person.FIRST_NAME) return '';
return `${person.LAST_NAME}, ${person.FIRST_NAME}`;
};
$select2.select2({
placeholder : 'Enter Last Name',
allowClear : true,
minimumInputLength : 3,
query: query => {
$.ajax({
url : `/remedy/people/last_name/${query.term}`,
type : 'GET',
headers: { 'content-type': 'application/json' },
data : JSON.stringify({ searchTerm: query.term })
})
.done(people => {
query.callback({ results: people });
});
},
formatResult,
formatSelection,
escapeMarkup : m => m
})
.on('select2-removed', e => {
// TODO
})
.on('select2-selecting', e => {
console.log(e); // TODO: Remove this
if (e.object && e.object.PERSON_ID) {
console.log(e.object.PERSON_ID); // TODO
}
});

I resolved this myself by passing an ID field to the select2 options like-so:
$select2.select2({
placeholder : 'Enter Last Name',
allowClear : true,
minimumInputLength : 3,
id: obj => obj.PERSON_ID,
query: query => {
$.ajax({
url : `/remedy/people/last_name/${query.term}`,
type : 'GET',
headers: { 'content-type': 'application/json' },
data : JSON.stringify({ searchTerm: query.term })
})
.done(people => {
query.callback({ results: people });
});
},
formatResult,
formatSelection,
escapeMarkup : m => m
})
.on('select2-removed', e => {
// TODO
})
.on('select2-selecting', e => {
console.log(e); // TODO: Remove this
if (e.object && e.object.PERSON_ID) {
console.log(e.object.PERSON_ID); // TODO
}
});

Related

AutoComplete in jQuery with dynamically added elements works only in first input field

I have a scenario where when we load the page for the first time it will have an input field along with a button to add more rows. In my case, the autocomplete works on the very first row and it is not working on the rows added using the button.
The code is as follows
// In Js file
$(".autocomplete").each((_, item) => {
const $item = $(item);
$item.typeahead(
{
minLength: 1,
highlight: true,
},
{
name: $item.attr("test-data"),
source: async (keywords, syncResults, asyncResults) => {
return $.ajax({
data: { keywords: keywords },
dataType: "json",
success: (response) => {
return asyncResults(response.items);
},
type: "post",
url: window.URLS["autocomplete"][$item.attr("test-data")],
});
},
limit: 10,
templates: {
notFound: "No match",
pending: "Loading...",
suggestion: (item) => {
return `<div>${item}</div>`;
},
},
},
);
});
// To handle add button click
$data.on("click", ".insert", () => {
$data.append($(document.importNode($data.get(0).querySelector("template").content, true)));
});
// This is inside a twig file to add a new input when the add button is clicked
<input
class="autocomplete block"
test-data="test"
type="text"
value="{{ value.event }}"
/>
Can anyone help me out?
You can have this
const atc = () => {
$(".autocomplete")
.filter((_, item) => { return !$(item).is(".tt-input") }) // ignore already assigned autocompletes
.each((_, item) => {
const $item = $(item);
...
});
}
and add
$(function() {
$("#add")..on("click",() => {
// add the field
atc()
});
atc()
})

React Redux functional component updating state not working

My data looks like this:
{
'004': [
{
year_week: '2020-W1',
actual_bank_amount: '6500000',
ext_in_rental_income: '',
ext_in_tax_refund: '',
ext_in_dividends_income: ''
},
{
year_week: '2020-W2',
actual_bank_amount: '6500000',
ext_in_rental_income: '',
ext_in_tax_refund: '',
ext_in_dividends_income: ''
}
],
'007': [
{
year_week: '2020-W22',
actual_bank_amount: '65050000',
ext_in_rental_income: '30000',
ext_in_tax_refund: '',
ext_in_dividends_income: ''
}
]
},
I am trying to update say date for year_week '2020-W1' in '004'.
No problem with action and reducer but data is not updated in the list.
Below is my reducer:
case 'UPDATE':
state.planningData[action.payload.currentSite].map((item, index) => {
if (item.year_week === action.payload.data.year_week) {
return Object.assign({}, item, action.payload.data);
}
return item;
});
console.log(state)
return {
loading: true,
planningData: state.planningData,
error: ''
}
What I am doing wrong please. Btw when I do console log or run redux extension I see the updated state.
Below is my action creator:
export const update = (data) =>
(dispatch, getState) => {
console.log("Update action called" + JSON.stringify(data))
const currentSite = getState().sites.currentSite;
dispatch({
type: 'UPDATE',
payload: {
data: data,
currentSite: currentSite
}
});
};
btw I am calling it from a editable cell component on "enter" and blur event below is my code
const save = async e => {
try {
const values = await form.validateFields();
toggleEdit();
dispatch(update({ ...record, ...values }));
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
This isn't pretty but it works. You had a bit of nested data in your state and it wasn't being updated properly.
case "UPDATE":
let updatedPlanningData = {};
for (let prop in state.planningData) {
if (prop === action.payload.currentSite) {
updatedPlanningData[action.payload.currentSite] = state.planningData[
action.payload.currentSite
].map((item, index) => {
if (item["year_week"] === action.payload.data.year_week) {
return Object.assign({}, item, action.payload.data);
}
return item;
});
} else {
updatedPlanningData.prop = state.planningData[prop];
}
}
return {
loading: true,
planningData: updatedPlanningData,
error: ""
};
Here is example code in codesandbox
Edit: more compact solution
let updatedPlanningData = {...state.planningData};
updatedPlanningData[action.payload.currentSite].map((item, index) => {
if (item["year_week"] === action.payload.data.year_week) {
return Object.assign(item, action.payload.data);
}
return item;
});

ChartJS - Returning labels and data from server on different calls

I am using classes to build charts and the thing with this one is: I need to return from the server dynamic labels and data every often. With this code I have accomplished to print on the console results I want for each function separately - array of carNames and array of avgSpeeds, but drawing the chart itself by the function drawSpeedChart has been really painful. Could anyone give me a way to pursue in order to get these printed results to render the chart? Thanks!!!
Here is the function that would supposedly render the chart:
drawSpeedChart() {
this.labels;
this.avgData;
this.getAvgData()
.then(avgData => {
this.avgData = avgData
console.log(this.avgData)
this.getCarNames()
}).then(carNames => {
this.carNames = carNames
console.log(this.labels)
}).then(this.createChart(this.labels, this.avgData))
}
Both console.log()return undefined for this snippet.
Main functions to return labels and data are respectively getCarNames and getAvgDataand they at least print in console the right result. Problem is to build the chart after that
Here is the full code.
window.onload = () => { new AvgSpeedChart(); }
class AvgSpeedChart {
constructor() {
this.selectElements()
this.drawSpeedChart()
}
selectElements() {
this.speedChartElement = document.querySelector('#speedChart')
}
createChart(carNames, avgData) {
return new Chart(this.speedChartElement, {
type: 'bar',
data: {
labels: carNames,
datasets: [{
label: "Velocidade média",
data: avgData
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: 'Velocidade média'
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
legend: {
display: false
}
}
})
}
drawSpeedChart() {
this.labels;
this.avgData;
this.getAvgData()
.then(avgData => {
console.log(this.avgData)
this.getCarNames()
return this.avgData = avgData
}).then(carNames => {
console.log(this.labels)
return this.labels = carNames
}).then(this.createChart(this.labels, this.avgData))
}
getCarNames() {
return axios({
method: 'get',
url: "xxxxxxxxxxx",
auth: {
username: 'xxxxx',
password: 'xxxxx'
}
}).then(response => {
this.carNames = response.data.map(car => car.name)
console.log(this.carNames)
return this.carNames
}).catch(error => {
console.log(error)
})
}
getAvgData() {
return axios({
method: 'get',
url: "xxxxxx",
auth: {
username: 'xxxxx',
password: 'xxxxx'
}
}).then(response => {
this.devicesId = response.data.map(device => device.id)
return this.devicesId
}).then(devicesId => {
this.getAllSpeed(devicesId.map(e => this.getAvgSpeed(e)))
}).catch(error => {
console.log(error)
})
}
getAllSpeed(arr) {
return axios.all(arr)
.then((avgSpeeds) => {
console.log(avgSpeeds)
return avgSpeeds
})
}
getAvgSpeed(deviceId) {
return axios({
method: 'get',
url: "xxxxxxx",
auth: {
username: 'xxxxx',
password: 'xxxxx'
},
params: {
from: '2018-10-09T00:00:00',
to: '2018-10-09T23:59:59',
deviceId: `${deviceId}`
}
}).then(response => {
this.allSpeeds = response.data.map(pos => pos.speed)
let sumSpeed = this.allSpeeds.reduce(this.sumSpeeds, 0)
let numSpeed = this.allSpeeds.length === 0 ? 1 : this.allSpeeds.length
let avgCalc = ((sumSpeed/numSpeed)*1.852)
return avgCalc
}).catch(error => {
console.log(error)
})
}
sumSpeeds(total, sum) {
return total + sum
}
}
The problem with your drawSpeedChart method is that the properties which you are using with this does not exist on your class. I've made them local variables. And you don't need the third then because you already have all the information to call createChart method.
drawSpeedChart() {
let avgData;
this.getAvgData()
.then((avgDataResponse) => {
console.log(avgDataResponse);
avgData = avgDataResponse;
return this.getCarNames();
}).then((carNames) => {
console.log(carNames)
this.createChart(carNames, avgData)
}).catch((err) => {
console.log('Error', err);
})
}
Checkout this fiddle to see working example

Updating state when dropdown select is changed React

This onChange event handles the selection of a dataschema then makes a subsequent request to get the queryschemas of the selected dataschema. handleChange is working correctly and renders the appropriate querySchemas in a dropdown list.
handleChange = (e) => {
const dataSchema = this.state.dataSchemas.find(dataSchema => dataSchema.name === e.target.value);
if (dataSchema) {
axios({
method: 'get',
url: `${dataSchema.selfUri}/queryschemas/`,
headers: { 'Accept': "" }
})
.then(response => {
console.log(response)
console.log(JSON.stringify(dataSchema.selfUri));
console.log(dataSchema.id)
this.setState({
querySchemaId: response.data.data[0].id,
querySchemaUri: response.data.data[0].selfUri,
querySchemaName: response.data.data[0].name,
querySchemas: response.data.data, //has list of querySchemas from request
selectedId: dataSchema.id
}, () => {
console.log(this.state.querySchemaId)
console.log(this.state.querySchemaUri)
console.log(this.state.querySchemaName)
console.log(this.state.selectedId)
});
})
.catch(error => console.log(error.response));
}
}
//This is the list of querySchemas returned by the above request
{
"data" : [ {
//array postion [0] --
"id" : "2147483601",
"selfUri" : "/dataschemas/2147483600/queryschemas/2147483601",
"name" : "QS-1"
}, {
//array position [1]
"id" : "2147483602",
"selfUri" : "/dataschemas/2147483600/queryschemas/2147483602",
"name" : "QS-2"
} ]
}
querySchemaChange = e => {
const querySchema = this.state.querySchemas.find(querySchema => querySchema.name === e.target.value);
if (querySchema) {
axios({
method: 'get',
url: `/dataschemas/${this.state.selectedId}/queryschemas/${this.state.querySchemaId}/queries`, //<--- {this.state.querySchemaId} is not updating to show the current querySchema that is selected
headers: { "Accept": "" }
})
.then(response => {
console.log(response)
})
.catch(error => console.log(error.response));
}
}
Then the second call is using the querySchemaId to make a request to the specific URI,
But querySchemaId: response.data.data[0].id, always grabs the first array from the response, obviously. So my issue is if I choose a different querySchema from the drop down it is always using the response in position [0] to make the next call. How can I keep the name that is selected updated in state and use the id attached to it, so it fires the right request?
These are the select elements rendering the dropdowns
render(){
return (
<label>
Pick a DataSchema to filter down available QuerySchemas:
<select value={this.state.value} onChange={this.handleChange}>
{dataSchemas &&
dataSchemas.length > 0 &&
dataSchemas.map(dataSchema => {
return <option value={dataSchema.name}>{dataSchema.name}</option>;
})}
</select>
</label>{" "}
<br />
<label>
Pick a QuerySchema to view its corresponding queries status:
<select value={this.state.querySchemaName} onChange={this.handleChange} onChange={this.querySchemaChange}>
{querySchemas &&
querySchemas.map(querySchema => {
return <option value={querySchema.name}>{querySchema.name}</option>;
})}
</select>
</label>{" "}
<br />
)
}
You forgot to save selected value in the state (for select) and use event data (id) directly (in query url), not from state (setState is async, it will be updated later):
querySchemaChange = e => {
const querySchema = this.state.querySchemas.find(querySchema => querySchema.name === e.target.value);
if (querySchema) {
const {id, name} = querySchema
this.setState({
querySchemaId : id,
querySchemaName: name
});
axios({
method: 'get',
url: `/dataschemas/${this.state.selectedId}/queryschemas/${id}/queries`,
querySchemaName is used for current select value.
Is saving querySchemaId needed now (not used in query)? Is it used elsewhere?

Twitch API returning info in wrong order using Array.map()

I'm calling the Twitch API (should mention I'm doing this in React) to get information on a few channels. I'm getting the data back, but it gets added to the array in the wrong order, different on every reload. Since I have two make two different calls, this ends up leaving me with mismatched information. I'm assuming it's because some calls take longer than other, and array.map() is running regardless if the first call was done yet, I'm just not sure how to fix that.
Here is my script:
export default class TwitchApp extends React.Component {
state = {
games: [],
statuses: [],
names: [],
logos: [],
streams: ["nl_kripp", "ESL_SC2", "Day9tv",
"DisguisedToastHS" ]
};
findStreams = () => {
const channels = this.state.streams;
const statusUrls = channels.map((channel) => {
return 'https://api.twitch.tv/kraken/streams/' + channel;
})
const infoUrls = channels.map((channel) => {
return 'https://api.twitch.tv/kraken/channels/' + channel;
})
statusUrls.map((statusUrl)=> {
let url = statusUrl;
return $.ajax({
type: 'GET',
url: url,
headers: {
'Client-ID': 'rss7alkw8ebydtzisbdbnbhx15wn5a'
},
success: function(data) {
let game;
let status = data.stream != null ? "Offline" : "Online";
this.setState((prevState)=> ( { statuses: prevState.statuses.concat([status]) } ) );
status = '';
}.bind(this)
});
});
infoUrls.map((url)=> {
return $.ajax({
type: 'GET',
url: url,
headers: {
'Client-ID': 'rss7alkw8ebydtzisbdbnbhx15wn5a'
},
success: function(data) {
let name = data.display_name != null ? data.display_name : 'Error: Can\'t find channel';
let logo = data.logo != null ? data.logo : "https://dummyimage.com/50x50/ecf0e7/5c5457.jpg&text=0x3F";
let game = data.game != null ? data.game : "Offline";
//let status = data.status != null ? data.status: "Offline";
this.setState((prevState)=> ( { games: prevState.games.concat([game]), names: prevState.names.concat([name]), logos: prevState.logos.concat([logo]) } ) );
game = '';
logo = '';
name = '';
}.bind(this)
});
});
};
You have really many options here...
could either look into AsyncJs and it is the async.series(); you are looking for, that will make all call go into specific order.
You could also go for a promised based HTTP requester, like Axios in which you can chain all your requests.
But really, I would go with the 3rd option which is that you make an array of objects as your state like this:
state = {
info: {
"nl_kripp": {
game: '',
status: '',
name: '',
logo: '',
},
"ESL_SC2": {
game: '',
status: '',
name: '',
logo: '',
},
"Day9tv": {
game: '',
status: '',
name: '',
logo: '',
},
"DisguisedToastHS": {
game: '',
status: '',
name: '',
logo: '',
}
},
streams: ["nl_kripp", "ESL_SC2", "Day9tv", "DisguisedToastHS"]
};
and do something like this:
var streams = this.state.streams;
var fetchedArray = [];
fetchedArray.map(streams , stream => {
let url = 'https://api.twitch.tv/kraken/streams/' + stream;
return $.ajax({
type: 'GET',
url: url,
headers: {
'Client-ID': 'rss7alkw8ebydtzisbdbnbhx15wn5a'
},
success: function(data) {
var currentState = Object.assign({}, this.state.info[stream]);
currentState.status = data.stream === null ? 'Offline' : 'Online';
currentState.name = data.display_name;
currentState.logo = data.channel.logo;
currentState.game = data.game;
}.bind(this)
});
});
Now fetchedArray will hold the same information but stacked together and easily handle with javascript after, rather than unsorted arrays.

Categories