ReactJs Onclick Not Working If Append To Table in Javascript - javascript

I'm pushing JsonArray data to datatable in reactjs through array as following.
tableTest= () => { //Function Name
axios({
method: 'post',
url: "/test" //URL
})
.then(response => {
var testArray= [];
var slNo = 0;
response.data.map((item, index) => {
var result = [];
slNo++;
var result = [];
result.push(slNo);
result.push(item.id);
result.push(item.name);
result.push(item.mob);
result.push("<button onclick={this.accept}>Accept</button>");
testArray.push(result);
})
this.setState({ testTableTable: testArray});
}).catch(response => {
console.log("Error", response);
})
}
If I click the button Accept I get "this.accept" is not a function.
Can anyone please tell me how to write onclick function in Javascript.
Thank you :)

Instead of onclick function use column onClick function of datatable the source code as shown below:
tableTest= () => {
axios({
method: 'post',
url: "/test" //URL
})
.then(response => {
var testArray= [];
var slNo = 0;
response.data.map((item, index) => {
var result = [];
slNo++;
var result = [];
result.push(slNo);
result.push(item.id);
result.push(item.name);
result.push(item.mob);
result.push("<button class='accept"+index+"'>Accept</button>");//define class here to use reference for column onClick function
testArray.push(result);
})
this.setState({ testTableTable: testArray});
}).catch(response => {
console.log("Error", response);
})
}
//Change table to Datatable
setDataTableData = () => { //set datatable
this.$el2 = $(this.el2) //el2 is reference of table
this.$el2.DataTable(
{
data: this.state.RowTableData, //RowTableData is array
"columnDefs": [
//column click function goes here
{
"targets": 4,// 4th column in a table
"createdCell": (td, cellData, rowData, row, col) => {
$(td).on('click', '.accept' + row, () => { //Click on <td>
this.accept(); //call function here
})
}
}
],
}
)
}
//Accept function Here
accept =() =>{
//function here
}

.then(response => {
var testArray= [];
window.YOUR_CLICK_FN = this.accept.bind(this);
var slNo = 0;
response.data.map((item, index) => {
var result = [];
slNo++;
var result = [];
result.push(slNo);
result.push(item.id);
result.push(item.name);
result.push(item.mob);
result.push("<button onclick={YOUR_CLICK_FN}>Accept</button>");
testArray.push(result);
})
this.setState({ testTableTable: testArray});
}).catch(response => {
console.log("Error", response);
})
Problem is in refreance binding.

React event handlers are named using camelCase. You should be calling onClick instead of onclick.
See link below:
https://reactjs.org/docs/handling-events.html
CodeSandbox example:
https://codesandbox.io/s/3rp301jjym

tableTest= () => { //Function Name
axios({
method: 'post',
url: "/test" //URL
})
.then(response => {
var testArray= [];
var slNo = 0;
response.data.map((item, index) => {
var result = [];
slNo++;
var result = [];
result.push(slNo);
result.push(item.id);
result.push(item.name);
result.push(item.mob);
result.push((<button onclick={this.accept}>Accept</button>));
testArray.push(result);
})
this.setState({ testTableTable: testArray});
}).catch(response => {
console.log("Error", response);
})
}
Problem is it is stored as string. So you have to push it as a react component to make it work.
And onclick doesn't work in react. You have to use onClick

Related

zxing decodes continuously, when not expected to do so

What follows is the script that is loaded via webpacker in a rails 6 application. It is inspired from this example page's source code
I was under the impression that codeReader.decodeFromVideoDevice (line 72 of example code) implied it would decode only once.
Yes in practice, the scanner keeps decoding until the stop button is activated.
[the non indented code is that which is used for communicating with the application]
Where is this script lacking?
window.addEventListener('turbolinks:load', function () {
let selectedDeviceId;
const codeReader = new ZXing.BrowserMultiFormatReader()
console.log('ZXing code reader initialized')
codeReader.getVideoInputDevices()
.then((videoInputDevices) => {
const sourceSelect = document.getElementById('sourceSelect')
selectedDeviceId = videoInputDevices[0].deviceId
if (videoInputDevices.length >= 1) {
videoInputDevices.forEach((element) => {
const sourceOption = document.createElement('option')
sourceOption.text = element.label
sourceOption.value = element.deviceId
sourceSelect.appendChild(sourceOption)
})
sourceSelect.onchange = () => {
selectedDeviceId = sourceSelect.value;
};
const sourceSelectPanel = document.getElementById('sourceSelectPanel')
sourceSelectPanel.style.display = 'block'
}
document.getElementById('startButton').addEventListener('click', () => {
codeReader.decodeFromVideoDevice(selectedDeviceId, 'video', (result, err) => {
if (result) {
console.log(result)
document.getElementById('result').textContent = result.text
let formData = new FormData();
let CodeParams = {
code_data: result.text
};
formData.append("code_json_data", JSON.stringify(CodeParams));
$.ajax({
url: "/home/process_scan_result",
type: "post",
data: formData,
processData: false,
contentType: false
});
}
if (err && !(err instanceof ZXing.NotFoundException)) {
console.error(err)
document.getElementById('result').textContent = err
}
})
console.log(`Started continous decode from camera with id ${selectedDeviceId}`)
})
document.getElementById('resetButton').addEventListener('click', () => {
codeReader.reset()
document.getElementById('result').textContent = '';
console.log('Reset.')
})
})
.catch((err) => {
console.error(err)
})
})

queryClient.setQueryData react query return undefined

i'm working with react query queryClient, i want to add new data from result of mutation to previous data with key ["feed", id], i combined res and previous to newQuestions and when i console.log newQuestions i get the right data, but when i put that to queryClient.setQueryData it returned undefined
const { isLoading, mutate } = useMutation(createQuestion, {
onSuccess: (res) => {
//get prev data
const previousQuestion = queryClient.getQueryData(["feed", id]).data;
//combine
const newQuestions = [res, ...previousQuestion];
console.log(newQuestions);
//put
queryClient.setQueryData(["feed", id], newQuestions);
}});
however if i put res or previous to queryClient.setQueryData it works
const { isLoading, mutate } = useMutation(createQuestion, {
onSuccess: (res) => {
//put
queryClient.setQueryData(["feed", id], res); //it works
}});
and
const { isLoading, mutate } = useMutation(createQuestion, {
onSuccess: (res) => {
//put
queryClient.setQueryData(["feed", id], (previous)=>previous); //it works
}});
but
const { isLoading, mutate } = useMutation(createQuestion, {
onSuccess: (res) => {
//put
queryClient.setQueryData(["feed", id], (previous)=>[res,...previous]); //doesnt work
}});

this.funtionName is not defined [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I am learing to use API an making a news website where you can search a term. I am using the code given below to do so.
var newsAccordion = document.getElementById("newsAccordion");
let news = {
apiKey: "xxxxxxxxxx",
fetchNews: function () {
fetch(
"https://gnews.io/api/v4/top-headlines?&country=in&lang=en&token=xxxxxxxxxxx"
)
.then((response) => response.json())
.then((data) => {
this.fetchCotent(data);
});
},
fetchCotent: (data) => {
console.log(data);
size = data.articles.length;
let newsHtml = "";
for (var i = 0; i < size; i++) {
const { title } = data.articles[i];
const { publishedAt } = data.articles[i];
const { url } = data.articles[i];
const { image } = data.articles[i];
const { description } = data.articles[i];
console.log(title, publishedAt);
var date = new Date(publishedAt).toLocaleString(undefined, {
timeZone: "Asia/Kolkata",
});
}
newsAccordion.innerHTML = newsHtml;
},
searchNews: (term) => {
console.log(term);
fetch(
"https://gnews.io/api/v4/search?&lang=en&q=" +
term +
"&token=xxxxxxxxxx"
)
.then((response) => response.json())
.then((data) => {
this.serchNews();
});
},
searchNews: (term) => {
//code goes here
};
document
.querySelector(".search button")
.addEventListener("click", function (e) {
e.preventDefault();
news.searchNews(document.querySelector(".search-bar").value);
});
window.onload = function () {
news.fetchNews();
};
But the problem is its gaving an error sying
Uncaught (in promise) ReferenceError: showSearch is not defined
at index.js:59
At index.js:59 it says:
Uncaught (in promise) TypeError: this.showSearch is not a function
My question is why is this happening and how can I solve it?
Thanks for any help in advance.
Replace arrow function to regular function for searchNews and showSearch. So that it gets the current scope using this, because arrow function doesn't have it's own context; it takes the context of enclosing function.
searchNews: function(term) {
console.log(term);
fetch(
"https://gnews.io/api/v4/search?&lang=en&q=" +
term +
"&token=368ddd2e4d1c1c559f1fb904cb1e09fa"
)
.then((response) => response.json())
.then((data) => {
this.showSearch(data);
});
},
showSearch: function(data) {
size = data.articles.length;
// your code...
},
Working code example:
const news = {
searchNews: function (term) {
console.log("search news: ", term);
fetchApi("https://gnews.io/api/v4/search")
.then((response) => response.json())
.then((data) => {
console.log("received data:");
this.showSearch(data);
});
},
showSearch: function (data) {
console.log("showSearch: ", data);
// your code...
}
}
function fetchApi(url) { // fetch api stub
return new Promise((resolve, reject) => {
const response = {
data: { id: 123, title: "test-title" },
statusCode: 200
}
let responseObj = new Response(JSON.stringify(response))
setTimeout(resolve(responseObj), 500);
})
}
document.querySelector("#search-button").addEventListener("click", function (e) {
e.preventDefault();
news.searchNews(document.querySelector("#search-bar").value);
});
<html>
<head></head>
<body>
<div>Enter search title:
<input type="text" id="search-bar">
</div>
<div style="margin-top: 20px">
<button id="search-button">Search News</button>
</div>
</body>
</html>
This is because of the misunderstanding of this in Javascript. Please read the this in Javascript.
Anyway you can modify the code as follows.
const obj = {
searchNews: (term) => {
console.log(term);
function cbFunc(data) {
this.showSearch(data);
}
fetch(
"https://gnews.io/api/v4/search?&lang=en&q=" +
term +
"&token=368ddd2e4d1c1c559f1fb904cb1e09fa"
)
.then((response) => response.json())
.then(cbFunc.bind(obj));
},
showSearch: (data) => {
size = data.articles.length;
let newsHtml = "";
for (var i = 0; i < size; i++) {
const { title } = data.articles[i];
const { publishedAt } = data.articles[i];
const { url } = data.articles[i];
const { image } = data.articles[i];
const { description } = data.articles[i];
var date = new Date(publishedAt).toLocaleString(undefined, {
timeZone: "Asia/Kolkata",
});
console.log(title, date, url, image, description);
}
}
}
Please place emphasis on bind call, where obj should be your wrapper object(at the top line of the code).

Issue whis a promise in VueJS

I stack here today.
I make an axios call to my api.
On succes response I run the function and make a chart on my page from recived data.
It work fine while I leave all aditional transformation inside the method
mounted() {
this.month = moment().month("June").format("YYYY-MM");
axios.get('/data/statistic2/'+this.month)
.then(response => {
this.set = response.data;
this.generateChart(response.data);
})
},
methods: {
generateChart(input) {
let data = [];
input.forEach(function(row) {
let item = {};
item.day = row.day;
let timeArray = [row.time1, row.time2,row.time3,row.time4,row.time5];
let result = timeArray.filter(function(item) {
return item !== null;
}).reduce((prev, current) => parseInt(prev) + parseInt(current));
item.time = result;
data.push(item);
})
this.datachart = data;
},
But when I try to incapsulate this bit of logic in separate method
mounted() {
this.month = moment().month("June").format("YYYY-MM");
axios.get('/data/statistic2/'+this.month)
.then(response => {
this.set = response.data;
this.generateChart(response.data);
})
},
methods: {
generateChart(input) {
let data = [];
input.forEach(function(row) {
let item = {};
item.day = row.day;
item.time = convertTimeFromDB(row);
data.push(item);
})
this.datachart = data;
},
convertTimeFromDB(row) {
let timeArray = [row.time1, row.time2,row.time3,row.time4,row.time5];
return timeArray.filter(function(item) {
return item !== null;
}).reduce((prev, current) => parseInt(prev) + parseInt(current));
},
I got "Uncaught (in promise) ReferenceError: convertTimeFromDB is not defined"
You should change convertTimeFromDB(row) to this.convertTimeFromDB(row), and change the function(row) {} to an arrow function (row => {}):
generateChart(input) {
let data = [];
input.forEach((row) => {
let item = {};
item.day = row.day;
item.time = this.convertTimeFromDB(row);
data.push(item);
})
this.datachart = data;
},
This has nothing to do with promises.
convertTimeFromDB is a property of the methods object. It isn't a variable (in scope or otherwise).
You have to refer to it in the context of the object (e.g. whatever.methods.convertTimeFromDB)

How to implement the 'show more' button?

I want to implement button behavior Show more.
When I click the button, new objects must be loaded without rebooting.
I do const [data, setData] = useState(users); to initialize the first 10 users.
When I press the button, that to this array data, I add the following 10 users
var users = response.data;
for (var i=0; i < users.length; i++) {
data.push(users[i]);
}
setData(data);
But nothing is rendered in the browser.
how to do it correct?
const Cards = ({users, bottomUrl }) => {
const [data, setData] = useState(users);
const handleSubmit = e => {
e.preventDefault();
const page = bottomUrl.slice(-1);
const axios = require('axios');
const url = '/users';
axios.get(url, {
params: { page: page }
}, {headers: {'Content-Type': 'application/json'}})
.then(function (response) {
var users = response.data;
for (var i=0; i < users.length; i++) {
data.push(users[i]);
}
setData(data);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
};
return (
<div>
<div className="users-list">
{data.map((element, elIndex) => (
<UserCard
key={elIndex}
lastName={element.lastName}
firstName={element.firstName}
description={element.description}
/>
))}
</div>
<div className="users-page-button-container">
<a className="button" onClick={handleSubmit} href={bottomUrl}>Show more</a>
</div>
</div>
)
};
You are pushing on the state object data. You must use an intermediate variable and pass that to setData
You are manipulating the state directly, which is wrong. Please update the handleSubmit method as below.
const handleSubmit = e => {
e.preventDefault();
const page = bottomUrl.slice(-1);
const axios = require('axios');
const url = '/users';
axios.get(url, {
params: { page: page }
}, {headers: {'Content-Type': 'application/json'}})
.then(function (response) {
users = response.data;
setData([...data, ...users]); // You need to save the previous data along with the new data and pass it together to setData function. So here data = previous data + new users data
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
};

Categories