This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I'm trying to pull in specific values from a JSON File. I am attaching data to the component, which then gets passed through the getProjectsList function, which should then look for a specific JSON file and render that data within a list item.
This is my Component
class OpenProjectsHome extends React.Component {
constructor () {
super();
this.getProjectList = this.getProjectList.bind(this);
}
getProjectList(project) {
var projectNameFile = openProjectsData[project]
var url = window.location.protocol + "//" + window.location.host + "/open-projects/" + projectNameFile;
let clientName = "";
let projectName = "";
var startDate = "";
var component = this;
var jqxhr = $.get( url, function(myData) {
// console.log(myData)
console.log(myData[0].Client)
console.log(myData[0].Project)
console.log(myData[0].StartDate)
clientName = myData[0].Client
projectName = myData[0].Project
startDate = myData[0].StartDate
})
.fail(function() {
alert( "error" );
});
var projectURL = "project?=" + projectName;
return (
<li>
<a href={projectURL} title="">
<h6 className="eyebrow">{clientName}</h6>
<h6>{projectName}</h6>
<span><strong>Started:</strong> {startDate}</span>
</a>
</li>
)
}
render() {
return(
<section className="project-lists project-lists--current">
<div className="panel">
<div className="panel__header">
<h4 className="panel__title">Open Projects</h4>
</div>
<div className="panel__content">
<ul className="unordered-list">
{/* /////
///// WORKS
///// */}
{Object.keys(this.props.data).map(this.getProjectList)}
</ul>
</div>
</div>
</section>
);
}
}
Its rendering out the two <li> but my variables clientName, ProjectName, StartDate are all rendering as null within the return (the console.log within the $.get are working)
Any help would be greatly appreciated.
you should use setState and the axios and arrow function
var jqxhr =axios.get(url, (myData)=>{
// console.log(myData)
this.setState({
clientName : myData[0].Client,
projectName : myData[0].Project,
startDate = myData[0].StartDate
})
console.log(myData[0].Client)
console.log(myData[0].Project)
console.log(myData[0].StartDate)
})
.fail(function() {
alert( "error" );
});
axios doc https://github.com/axios/axios
Related
`import React from 'react'
export default function Quiz(props){
// generate random index without duplicates
function generateRandomIndex(){
const randomNumArr=[]
for (var a = [0, 1, 2, 3], i = a.length; i--; ) {
var random = a.splice(Math.floor(Math.random() * (i + 1)), 1)[0];
randomNumArr.push(random)
}
return randomNumArr
}
let randomNumbers = generateRandomIndex()
let spreadOptions = ()=>{
let optionsHtmlArray = []
for(let i=0; i<props.answers.length; i++){
optionsHtmlArray.push(`<span className='answers' key=${i} style={${{backgroundColor: props.correct===props.answers[i] ? "green" : "red"}}}>
{ ${props.answers[i]} } </span>`)
}
return optionsHtmlArray
}
return (
<div className='Quiz'>
<h3 className='question'>{props.question}</h3>
<div className='answers_div'>
{ spreadOptions()[randomNumbers[0]] }
{ spreadOptions()[randomNumbers[1]] }
{ spreadOptions()[randomNumbers[2]] }
{ spreadOptions()[randomNumbers[3]] }
</div>
<hr className='hr'/>
</div>)
}
'
'//this is from App.js
// fetch to API when first render to save data to the state,
// and fetch depending on the sate of showOverlay
React.useEffect(() => {
fetch("https://opentdb.com/api.php?amount=5&category=9&difficulty=easy&type=multiple")
.then(res => res.json())
.then(data => {
setQuestions(data.results)
//after set questions state that comes from fetch request
//and set the custom questions with some properties I need
setCustomQuestions(prevQuestions=>{
let newArr=[]
for(let i=0; i<data.results.length; i++){
newArr.push({question: data.results[i].question,
questionId: nanoId(),
answers: [data.results[i].correct_answer].concat(data.results[i].incorrect_answers),
correct: data.results[i].correct_answer})
}
return newArr
})
})
}, [])
// Quiz component properties
const customQuestionsArr = customQuestions.map(question => {
return < Quiz
key={question.questionId}
question={question.question}
answers={question.answers}
correct={question.correct}
/>
})'
Hi all, I am trying to render all options of the answers in Quiz component, however,
spreadOptions() returns an array of html strings for the answers
I gotta parse to JSX to make it work.
I tried to install react-html-parser, didn't work it only gave me a bunch of error every time when I try to install dependencies through npm
I tried dangerouslySetInnerHTML, but also didn't work
Would you be able to provide the props that you are trying to pass to Quiz component?
Below is a snippet of code with modified spreadOptions and jsx. I wasn't able to test this code tho but will update it if you can provide the sample props.
let spreadOptions = props.answers.map((a, i) => (
<span
key={i}
className='answers'
style={{
backgroundColor: props.correct === a ? 'green' : 'red',
}}
>
{a}
</span>
));
return (
<div className="Quiz">
<h3 className="question">{props.question}</h3>
<div className="answers_div">
{spreadOptions}
</div>
<hr className="hr" />
</div>
);
React.js
On the main page example.js there are 4 links: link1, link2, link3, link4
When the user clicks on one of the links they are sent to a site called template.js.
Each link sends the user to the same site, template.js, however the data is different depending on what link was clicked.
I have tried just to display the entire data from one of my .json files, without any functionality and style -- but I didn't get any response whatsoever...
I have tried:
var data = require(url);
for(var i = 0; i < data.length; i++) {
var obj = data[i];
console.log("Name: " + obj.first_name + ", " + obj.last_name);
}
OR
fetch(url)
.then(response => response.json().then(data => ({status:
response.status, body: data})))
.then(object => console.log(object));
OR
fetch(url)
.then(response = response.json())
Question:
How would I tell the template.js file to display the relevant information.
You can pass your query through the link and then read it directly from the url.
I do it this way:
Your links
// Here we want to send our search terms, this is just an example with 'someId'
<a src="/template?first_name=john"></a>
<a src="/template?first_name=jenny"></a>
<a src="/template?first_name=gabriel"></a>
<a src="/template?first_name=jose"></a>
You can read the search values with window.location.search or window.location.hash depending on your router.
I prefer use the parse function from the query-string module
Your template
import React, { Component } from 'react';
import * as qs from 'query-string';
class Dashboard extends Component {
render() {
const {
location,
} = this.props;
const { search } = location;
const query = qs.parse(search, { ignoreQueryPrefix: true });
const info = YOURJSONDATA.filter(data => (
// Here we compare the field we want with the query search
data.first_name === query.first_name
));
return (
<div>
{
!!(info) && info.map(o => (<div>{o.first_name}</div>))
}
</div>
);
}
}
Here's how I did it....
In Learn.js__
//reading url
componentDidMount() {
const values = queryString.parse(this.props.location.search)
console.log(values.filter)
console.log(values.origin)
}
//redirection
redirect = (url) => {
this.props.history.push(url)
console.log(this.props)
}
<LearnCard onClick={() => this.redirect("/learn/Template/Cooks")} name="Cooks" image={process.env.PUBLIC_URL + '/image/cook.jpg'}/>
<LearnCard onClick={() => this.redirect("/learn/Template/Websites")} name="Websites" image={process.env.PUBLIC_URL + '/image/website.jpg'}/>
<LearnCard onClick={() => this.redirect("/learn/Template/Tv-Series")} name="Tv-Series" image={process.env.PUBLIC_URL + '/image/tv_series.jpg'}/>
<LearnCard onClick={() => this.redirect("/learn/Template/Cookbooks")} name="Cookbooks" image={process.env.PUBLIC_URL + '/image/cookbook.jpg'}/>
In Template.js__
componentDidMount () {
const url_name = this.props.match.params.name
console.log(this.props.match.params.name)
if (url_name === "Cooks") {
this.setState({data: cooks})
console.log(cooks)
}
if (url_name === "Cookbooks") {
this.setState({data: cookbooks})
console.log(cookbooks)
}
if (url_name === "Tv-Series") {
this.setState({data: tv_series})
console.log(tv_series)
}
if (url_name === "Websites") {
this.setState({data: websites})
console.log(websites)
}
}
render () {
return (
<div>
<div className="templateWrapper">
{
this.state.data && this.state.data.map((data, key) => {
return <TemplateCard className="templateCard" name={data.name} description={data.description} image={data.image} cuisine={data.cuisine} author={data.author} channel={data.channel} href={data.web_url} href={data.chef_url}/>
})
}
</div>
</div>
);
}
I'm new to Vue. I want to read employeeId from a login form and ust it to load some json files named according as employeeId.json like (10000001.json, 20000001.json) and set the json object as a global variable so I can easily access it in all components.
Firstly, I don't know how to dynamically load json files. Using import sees not work. Some one suggested using require should work. But there are not many examples, I don't know where to put require...
Secondly, how do I set the json as global after the employeeId props in? I'm very confused where to put it (inside the export default or not? inside methods or not? or inside created/mounted or not?) and where to use this or not...
This is the script section of my headerNav.vue file.
<script>
//**I placed them here now, it works, but employeeId is hard coded...
import json10000001 from "./json/10000001.json";
import json20000001 from "./json/20000001.json";
import json30000001 from "./json/30000001.json";
// var employeeId = employeeIdFromLogin;
var jsonForGlobal;
var employeeId = 10000001;
var jsonFileCurrentObj;
if (employeeId == "10000001") {
jsonForGlobal = jsonFileCurrentObj = json10000001;
} else if (employeeId == "20000001") {
jsonForGlobal = jsonFileCurrentObj = json20000001;
} else if (employeeId == "30000001") {
jsonForGlobal = jsonFileCurrentObj = json30000001;
}
export default {
// props:{
// employeeIdFromLogin: String,
// },
props:['employeeIdFromLogin'],
jsonForGlobal,
// employeeIdFromLogin,
data() {
return {
docked: false,
open: false,
position: "left",
userinfo: {},
jsonFileCurrent: jsonFileCurrentObj,
// employeeIdFromLogin: this.GLOBAL3.employeeIdFromLogin
// jsonFile: currentJsonFile
};
},
mounted() {
//**I tried put it here, not working well...
// var employeeId = this.employeeIdFromLogin;
// // var jsonForGlobal;
// console.log("headernav.employeeIdFromLogin="+this.employeeIdFromLogin);
// // var employeeId = 10000001;
// var jsonFileCurrentObj;
// if (employeeId == "10000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json10000001;
// } else if (employeeId == "20000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json20000001;
// } else if (employeeId == "30000001") {
// this.jsonForGlobal = this.jsonFileCurrentObj = json30000001;
// }
},
methods: {
switchPage(pageName) {
this.$emit("switchPage", pageName);
}
//**I don't know how to use the require...
// var employeeId = 10000001;
// getJsonFile(employeeId) {
// this.currentJsonFile = require("../assets/json/" + employeeId + ".json");
// }
}
};
You might want to use vuex to manage global store. But if you don't want includes Vuex, there is a simpler way to have global state:
Define globalStore.js
// globalStore.js
export const globalStore = new Vue({
data: {
jsonForGlobal: null
}
})
then import it and use in component:
import {globalStore} from './globalStore.js'
export default {
props: ['employeeIdFromLogin'],
data: function ()
return {
jsonLocal: globalStore.jsonForGlobal,
jsonFileCurrent: null
}
},
watch: {
employeeIdFromLogin: {
handler(newVal, oldVal) {
const data = require('./json/' + this.employeeIdFromLogin + '.json')
this.jsonFileCurrent = data
globalStore.jsonForGlobal = data
}
}
}
}
My data back from search result has columns: enTitle,Image,url,enDescription,HasLandingPage,AddInfo.
I want to filter search results by AddInfo to show in different lists. later if I can add a button that would be better.
Render Data:
const ListArticle = (props) =>{
return (
<div className="card">
<div className="search-img-lft">
<a href={props.link} target="_blank">
<img src={props.image} alt="" />
</a>
</div>
<div className="search-imgcont-rgt">
<a href={props.link} target="_blank">
<h3>
{props.title}
{props.kind} // just to see if kind works
</h3>
<p>{props.desc}</p>
</a>
{props.link}
</div>
</div>
);
}
List Class:(ignore the i,brac & lim they are for pagination)
class List extends React.Component {
render(){
const liArt =[];
const searchText = this.props.searchText.toLowerCase().replace(/[^a-z0-9]/g, '');
var i = 0;
const brac = this.props.start;
const lim = brac + this.props.qtyPerPage;
//the filter below works for resources but I want all to be filtered and show in the list in previous code snippet
this.props.list.filter(u=>u.AddInfo == "resource").map((article)=>{
var artText = (article.enTitle + " " + article.URL + " " + article.enDescription + " " + article.AddInfo).toLowerCase().replace(/[^a-z0-9]/g, '');
if(artText.indexOf(searchText)===-1){
return;
}
i++;
if(brac<i && i<lim){
liArt.push(
<ListArticle key={article.Image+article.URL}
title={article.enTitle}
image={article.Image+"?h=100&mode=crop&scale=down"}
link={JSON.stringify(article.HasLandingPage).toUpperCase()=="TRUE" ? "/en/"+article.URL : "/" + article.URL}
desc={article.enDescription}
kind={article.AddInfo.includes("SKU") ? " Product" : (article.AddInfo.includes("resource") ? " Resource" : " Page")} />
);//push
} //limit check
});//map
return (
<div className="search-page-listbox">
{liArt}
</div>
);
}
}
If i got you right, you want to create multiple lists while each list shows items of another"AddInfo".
First, I would recommend to separate your task into three components (instead of two):
First component is the ListArticle which will be the list item,
Second will be the component List -> that will receive the list you want to show (after they have been filtered),
Last component will be ListContainer -> this one will hold multiple lists (as many as the options of AddInfo).
Then, in ListContainer you can go over all unique AddInfo, and create List component for every option - passing only filtered items:
ListArticle.js
import React from 'react';
const ListArticle = (props) =>{
return (
<div className="card">
<div className="search-img-lft">
<a href={props.link} target="_blank">
<img src={props.image} alt="" />
</a>
</div>
<div className="search-imgcont-rgt">
<a href={props.link} target="_blank">
<h3>
{props.title}
{props.kind} // just to see if kind works
</h3>
<p>{props.desc}</p>
</a>
{props.link}
</div>
</div>
);
}
export default ListArticle;
List.js
import React from 'react';
import ListArticle from './ListArticle';
export default class List extends React.Component {
render() {
return (
this.props.list.map(article => <ListArticle key={article.Image + article.URL}
title={article.enTitle}
image={article.Image + "?h=100&mode=crop&scale=down"}
link={JSON.stringify(article.HasLandingPage).toUpperCase() == "TRUE" ? "/en/" + article.URL : "/" + article.URL}
desc={article.enDescription}
kind={article.AddInfo.includes("SKU") ? " Product" : (article.AddInfo.includes("resource") ? " Resource" : " Page")} />
)
)
}
}
ListContainer.js
import React from 'react';
import List from './List';
class ListContainer extends React.Component {
constructor(props){
super(props);
}
render() {
let lists = {};
let searchText = this.props.searchText;
if(this.props){
let filteredList = this.props.list.filter(article=>(article.enTitle + " " + article.URL + " " + article.enDescription + " " + article.AddInfo).toLowerCase().replace(/[^a-z0-9]/g, '').indexOf(searchText)!==-1);
filteredList && filteredList.forEach(u => {
if(lists[u.AddInfo]===undefined) lists[u.AddInfo]=[];
lists[u.AddInfo].push(u);
});
}
return(
Object.keys(lists).map(function(key, index) {
return <List list={lists[key]} />
})
)
}
}
export default ListContainer;
Usage:
<ListContainer list={list} searchText={searchText} />
Hope it helped :)
I'd return something like this from your List class (I tried explaining my thought process in comments inside the code):
return (<React.Fragment>
{
// second (kinda), I'd convert the inside generated collection (object) into an array
// -> where the array elements are now ["AddInfo type", [array of elements with that type]]
Object.entries(
// first, convert the list into an object, collecting each type of "AddInfo" into
// -> a unique property, and storing all objects w/ that type in an array
this.props.list.reduce((output, u) => {
if (!output[u.AddInfo]) output[u.AddInfo] = [];
output[u.AddInfo].push(u);
return output
}, {})
)
// third, I'd map the new array of ["AddInfo type", [array of elements with that type]] into
// -> the jsx output you want, like this:
.map(([type, array]) => {
return <div className="search-page-listbox">
{array.map((article, i) => {
// ... everything inside your ".map((article...)" function can go here
})}
</div>
})
}
</React.Fragment>)
A few notes:
You can replace var i = 0 and i++ lines with the i index that automatically comes from the second parameter in the map function (see my version of array.map((article, i) => ...)
If you haven't seen things like array destructuring (ex: .map(([type, array]) => ...)) let me know, I can explain. It's a pretty shnazzy thing you can do to save some lines.
My first step was to figure out how to create an object container which holds sorted data based on AddInfo - that's why my // first comment comes technically after the // second comment. Hope that makes sense.
Let me know if you have questions or if there was a typeo that's breaking my code. I haven't tested it obviously since I don't have your react code / variables.
I am developing my application in my MVC. I am using cascading dropdown list in my application. On selecting one i have 2 dropdown one is location and another one is employee. While selecting a location particular employee should be fetched in employee dropdown. I am using json result to retrieve the employee.
My code is
View Page
#Html.DropDownList("location", ViewBag.Location as SelectList, "Select the Location", new { id = "location" })
<div id=" employeediv" style="width:600px; height:50px">
<div style="float:left">
<label> Employee:</label>
</div>
<div style="margin-left:220px">
<select id="Employee" name="employee" style="width:150px"></select>
</div>
</div>
Script:
#section scripts{
<script type="text/javascript">
$('#location').change(function () {
#*var url = '#Url.Action("Employe", "Appt")';*#
//var url = "/Appt/Employee/"
debugger;
$.getJSON('/Appt/Employee/' + $('#location').val(), function (data) {
var item = '<option> Any </option>';
$.each(data, function (i, employee) {
item += "<option value ='" + employee.Value + "'>" + employee.Text +
"</option>";
});
$("#employee").html(items);
});
});
</script>
}
Controller Code
public ActionResult CalendarView(int? id, int? CustomerUserid)
{
tblBusinessCategory bc = new tblBusinessCategory();
ViewBag.Location = new SelectList(from s in db.tblBusinessLocations
where s.BusinessID == id
join loc in db.tblLocations
on s.LocID equals loc.LocationId
select loc.LocationName);
return View();
}
public JsonResult Employee(int id)
{
SYTEntities db = new SYTEntities();
var emp = from s in db.Employees
where s.LocationId == id
select s;
return Json(new SelectList(emp.ToArray(), "EmpId", "EmpName"), JsonRequestBehavior.AllowGet);
}
My problem is While changing the location url is not redirecting to the controller and it is came out from its scope
$.getJSON('/Appt/Employee/' + $('#location').val(), function
Can anyone help me to solve this?
Thanks.