I'm making a table that has to be dynamic, they are passing me data like this
[
{
"store_name": "daniel",
"store_id": "054050",
"store_address": "av las americas",
"store_logo": "https://centroamerica-resources.s3.amazonaws.com/walmart/express.png",
"occupancy": {
"recluta": 400,
"occupancy": 0,
"percentage": 0
},
"alerts": {
"conglomerations": 0,
"occupancy": 0
},
"visits": 0
},
{
"store_name": "expreso polar",
"store_id": "re485754re",
"store_address": "boulevard california",
"store_logo": "https://centroamerica-resources.s3.amazonaws.com/walmart/express.png",
"occupancy": {
"recluta": 300,
"occupancy": 0,
"percentage": 0
},
"alerts": {
"conglomerations": 0,
"occupancy": 0
},
"visits": 3836
},
]
This is an example of the data that they have given me in a .txt what I need is to show all this data in a table, I have created one with false data but what I need is to make it dynamic that it alone adds more data without need to create more components
for the moment, each data only has to be shown in div
<div class="">
<div class="flex">
<div class="">Name</div>
<div class="">Id</div>
<div class="">Adress</div>
<div class="">Logo</div>
<div class="">Rcluta</div>
<div class="">Ocupancy</div>
<div class="">Percentage</div>
</div>
<div class="flex">
<div class="">{store_name}</div>
<div class="">{store_id}</div>
<div class="">{store_address}</div>
<div class="">{store_logo}</div>
<div class="">{recluta}</div>
<div class="">{occupancy}</div>
<div class="">{percentage}</div>
</div>
</div>
The best practice is that feed data something like this
[
{
data: [
{ name: 'Store Name', value: 'expreso polar'},
{ name: 'Store Id', value: 're485754re'}
]
}
]
name be the label and value be the data needs to shown in the table for corresponding label
This is something very common that I come across while coding and here is what I do.
Im not sure how you are getting your json, whether it be by a fetch or if its hard coded but store it as a json object inside a variable
const [metadata, setMetadata] = useState([])
const data = response.json()
setMetadata(data);
const Table = useMemo(() => metadata.map(
({name, id, tags, address, logo}) => (
<div>
<div>Name: {name}</div>
<div>Id: {id}</div>
<div>Tags: {tags}</div>
<div>Address: {address}</div>
<div>: {logo}</div>
</div>
)
),
[metadata]);
Once you get your metadata in some sort of json format you can simply use the map function to map it all into jsx. Then call it by using <Table/>.
Using useMemo is always a good idea because it will update whenever one of the dependencies changes, in this case metadata.
Related
I'm attempting to create an 'edit listing' page where someone's submitted information is displayed back. I'm a bit stuck on how to populate checkboxes in a form with a check on the boxes that were selected the first time.
I'm aware that checkboxes look for false/true in order to display a check, but my array of something like: [x,y,z] is displayed as just [true] or [false] which leads to all boxes being checked at once and vice versa when using v-model.
The form
<input
type="checkbox"
id="Set Photographer"
value="Set Photographer"
v-model="returnedListing[0].crew_positions"
/>
<label for="Set Photographer">Set Photographer</label>
<input
type="checkbox"
id="Producer"
value="Producer"
v-model="returnedListing[0].crew_positions"
/>
<label for="Producer">Producer</label>
<input
type="checkbox"
id="Production Designer"
value="Production Designer"
v-model="returnedListing[0].crew_positions"
/>
<label for="Production Designer">Production Designer</label>
returnedListing
const [actors, returnedListing] = await Promise.all([
$axios.$get(`/api/v1/actors/`, {
params: {
user: body
}
}),
$axios.$get(`/api/v1/listings/`, {
params: {
random_public_id: params.id
}
})
]);
return { actors, returnedListing };
Dummy API object
{
"id": 15,
"title": "NUmber 15",
"start_date": "2021-03-04",
"end_date": "2021-02-16",
"location": "The Bronx",
"overview": "sdfds",
"studio": "sdfdsf",
"poster": null,
"crew_positions": "Set Photographer, Producer, Production Designer",
"post_production_positions": "Editing, AD",
"random_public_id": null,
"date_submitted": null,
"user": 1
}
Essentially I'm looking to figure out how to loop through returnedListing[0].crew_positions if it's value is ['Set Photographer', 'Producer'] and have those 2 boxes checked while 'Production Designer' remains unchecked.
The first problem (as mentioned in the comments) that the crew_positions is not an array, but a comma-separated string. Then you can iterate over them & set the checkboxes.
const returnedListingArray = [{
"id": 15,
"title": "NUmber 15",
"start_date": "2021-03-04",
"end_date": "2021-02-16",
"location": "The Bronx",
"overview": "sdfds",
"studio": "sdfdsf",
"poster": null,
"crew_positions": "Set Photographer, Producer, Production Designer",
"post_production_positions": "Editing, AD",
"random_public_id": null,
"date_submitted": null,
"user": 1
},
{
"id": 16,
"title": "NUmber 16",
"start_date": "2021-03-04",
"end_date": "2021-02-16",
"location": "The Bronx",
"overview": "sdfds",
"studio": "sdfdsf",
"poster": null,
"crew_positions": "Set Photographer, Production Designer",
"post_production_positions": "Editing, AD",
"random_public_id": null,
"date_submitted": null,
"user": 1
}
]
Vue.component("CrewPositionInput", {
props: ["id", "crewPosition", "checked"],
methods: {
handleCbClick() {
this.$emit("update:position-status", this.crewPosition)
},
},
template: `
<label
:for="id"
>
<input
type="checkbox"
:id="id"
:value="crewPosition"
:checked="checked"
#click="handleCbClick"
/>
{{ crewPosition }}
</label>
`
})
Vue.component("CrewPositions", {
props: ["id", "possibleCrewPositions", "crewPositions"],
methods: {
toggleCrew({
crew
}) {
const positions = this.crewPositions.includes(crew) ?
this.crewPositions.filter(item => item !== crew) : [...this.crewPositions, crew]
this.$emit("update:crewPositions", positions)
},
},
template: `
<div>
<crew-position-input
v-for="position in possibleCrewPositions"
:key="position + id"
:id="position + id"
:crew-position="position"
:checked="crewPositions.includes(position)"
#update:position-status="(crew) => toggleCrew({ crew })"
/>
</div>
`
})
new Vue({
el: "#app",
data() {
return {
returnedListings: [],
possibleCrewPositions: [],
}
},
mounted() {
this.returnedListings = returnedListingArray.map(({
crew_positions,
id,
// ...rest // commenting out - this is just a snippet, no need for large objects
}) => ({
id,
crew_positions: crew_positions.split(", "), // splitting string to array
}))
// just to make it a little more dynamic:
this.possibleCrewPositions = [...new Set(this.returnedListings.reduce((a, c) => {
return [...a, ...c["crew_positions"]]
}, []))]
},
template: `
<div>
<crew-positions
v-for="listing in returnedListings"
:key="listing.id"
:id="listing.id"
:possible-crew-positions="possibleCrewPositions"
:crew-positions.sync="listing['crew_positions']"
/>
{{ returnedListings }}
</div>
`
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
SHORT EXPLANATION
CrewPositionInput is a stateless component that accepts an id, a crewPosition & a checked prop from its parent. The only thing it does is that on click it emits a custom event with the this.crewPosition as payload.
The CrewPositions component is actually a list of CrewPositionInput components, that passes down props to its children and handles the update:position-status custom event coming from them. On any update:position-status custom event, it re-emits an array (that is actually a crewPositions array) to its parent.
The topmost component handles data processing (like crew_positions splitting) & state management (like updating the crew_positions in the stored array of objects (returnedListings). The update is done via .sync (more on sync here) - this is a handy method of doing it, but it has its constraints (like naming of the variables & events must follow. a certain pattern).
possibleCrewPositions is just a way of creating the available checkboxes based on the data source (dynamically).
I'm trying to access data further down into my JSON file. I am able to easily access data in the first two data sets in rows and area:
data.json
"rows": [
{
"uid":"001",
"type": "Lorem ipsum",
"area": [
{
"name": "London",
"number": "12345",
"wait": {
"start": {
"start_time": 1585129140,
"delay": 300
},
"end": {
"end_time": 1585130100,
"delay": 300
}
},
"in": 1585129140,
"out": 1585130100,
},
However when I try to access the data under wait which includes this block:
"wait": {
"start": {
"start_time": 1585129140,
"delay": 300
},
"end": {
"end_time": 1585130100,
"delay": 300
}
},
No data is getting returned on screen from my jsx file, but it is available in the console log
TimeTracker.jsx
const TimeTracker = (props) => {
const trainTime = useState(props.data);
console.log(props.data);
return (
<>
<div className={style.timeLabel}>
<div className={style.startTime}>{trainTime.start_time}</div>
<div className={style.endTime}></div>
</div>
</>
)
};
export default TimeTracker;
console.log
wait:
start:
start_time: 1585129140
delay: 300
__proto__: Object
end:
end_time: 1585130100
delay: 300
__proto__: Object
__proto__: Object
I've used the same pattern for passing props in other components and it works fine on the first two levels so I don't understand why it's not working. How do I get data from further in this JSON?
useState returns a tuple with the object and a function to set the value on the object. You probably need to change your component to something like this:
const TimeTracker = (props) => {
const [trainTime, setTrainTime] = useState(props.data);
console.log(props.data);
return (
<>
<div className={style.timeLabel}>
<div className={style.startTime}>{trainTime.start_time}</div>
<div className={style.endTime}></div>
</div>
</>
)
};
export default TimeTracker;
A nested property can not be accessed by one level of a.b so instead of
<div className={style.startTime}>{trainTime.start_time}</div>
it should be
<div className={style.startTime}>{trainTime.wait.start.start_time}</div>
I'm trying to conditionally show and hide columns based on the data returned, if the data set contains any objects meeting conditions.
Here is a sample of the data returned from my search results
[
{
"id": "typeahead-241-1091-option-0",
"label": "Android Home Page",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-1",
"label": "Google",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-2",
"label": "Forgotten Google Play Password",
"model": {
"type": "kb",
}
}
]
Now I'm presenting the data in columns, based on the type.
<div class="flexitem">
<h4>External Links</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'link'">{{match.label}}</div>
</div>
<div class="flexitem">
<h4>Knowledge Base</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'kb'">{{match.label}}</div>
</div>
<!-- the below has no results. I want it hidden altogether
currently it shows the <h4>Products</h4> with nothing below it-->
<div class="flexitem">
<h4>Products</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'product'">{{match.label}}</div>
</div>
What I need to accomplish is putting conditions on the flexitem divs altogether to only show if there are results for that type. So if there are no results with the type == 'product', then don't even show that div. A ng-if on that row would work, but what will be the best way to cycle through all of the children of match to determine if there is a result? indexOf doesn't work through children arrays.
Put the logic on the angular side using Array.filter to separate arrays;
Angular controller:
$scope.linkMathches = $scope.matches.filter(function(m){
return m.model.type === 'link'
});
$scope.kbMathches = $scope.matches.filter(function(m){
return m.model.type === 'kb'
});
HTML:
<div class="flexitem" ng-if="linkMathches.length">
<h4>External Links</h4>
<div ng-repeat="match in linkMathches">
{{match.label}}
</div>
</div>
<div class="flexitem" ng-if="kbMathches.length">
<h4>Knowledge Base</h4>
<div ng-repeat="match in kbMathches">
{{match.label}}
</div>
</div>
Going further for dynamic values in model.type:
Angular controller:
$scope.typeMatches = {
link: {title: 'External Links', matches: []},
kb: {title: 'Knowledge Base', matches: []},
product: {title: 'Products', matches: []}
};
$scope.matches.forEach(function(match){
$scope.typeMatches[match.model.type].matches.push(match);
});
HTML:
<div class="flexitem"
ng-if="value.matches.length"
ng-repeat="(key,value) in typeMatches">
<h4>{{value.title}}</h4>
<div ng-repeat="match in value.matches">
{{match.label}}
</div>
</div>
I'm trying to use jquery circliful plug-in to create a set of circlular statistics from json data, but it's not working as expected, wanted to display the "value" key from json and embed that data values into circular statistics graph.
{
"employee":[
{
"name": "test123",
"value": "20"
},
{
"name": "test456",
"value": "30"
},
{
"name": "test789",
"value": "40"
}
]
}
HTML snippet:
<section class="container">
<div class="row">
<div class="col-lg-3">
<div id="circle"></div>
</div>
</div>
</section>
JavaScript:
$("#circle").circliful({
animationStep: 5,
foregroundBorderWidth: 15,
backgroundBorderWidth: 15,
percent: 80 // mapping values for circular statistics graph
});
Any help on this? Thanks in advance.
So I have a JSON file from the Etsy API that returns the listings and their info. I want to get the title, url for the product, first image of the product, price, shop title, and shop url for each product, which is in this JSON (this is the first product):
{
"count": 657352,
"results": [
{
"title": "Clink illustration print - rosy pink cheeks nerds kissing - perfect gift for your love, a wedding, valentine, or anniversary",
"price": "20.00",
"url": "https:\\/\\/www.etsy.com\\/listing\\/55086613\\/clink-illustration-print-rosy-pink?utm_source=producttemp&utm_medium=api&utm_campaign=api",
"Images": [
{
"listing_image_id": 333410839,
"hex_code": "EAEBEB",
"red": 234,
"green": 235,
"blue": 235,
"hue": 180,
"saturation": 0,
"brightness": 92,
"is_black_and_white": false,
"creation_tsz": 1335891579,
"listing_id": 55086613,
"rank": 1,
"url_75x75": "https:\\/\\/img1.etsystatic.com\\/000\\/0\\/5470068\\/il_75x75.333410839.jpg",
"url_170x135": "https:\\/\\/img1.etsystatic.com\\/000\\/0\\/5470068\\/il_170x135.333410839.jpg",
"url_570xN": "https:\\/\\/img1.etsystatic.com\\/000\\/0\\/5470068\\/il_570xN.333410839.jpg",
"url_fullxfull": "https:\\/\\/img1.etsystatic.com\\/000\\/0\\/5470068\\/il_fullxfull.333410839.jpg",
"full_height": 594,
"full_width": 700
}
],
"Shop": {
"shop_name": "GenevieveSantos",
"url": "https:\\/\\/www.etsy.com\\/shop\\/GenevieveSantos?utm_source=producttemp&utm_medium=api&utm_campaign=api"
}
},
I used this to make the request for the data:
https://openapi.etsy.com/v2/featured_treasuries/listings?api_key=&includes=Images:1:0,Shop(shop_name,url,)&fields=title,price,url&limit=42
Now I'm using Vue.js to repeat the first 42 listings on a 3 x 14 grid in an html file but I'm having trouble reaching into the arrays just to return the first image and the title. Here is the HTML:
<section class="listings">
<div v-repeat="42" class="column" id="listings">
<a href={{item_url}}>
<img src={{url_fullxfull}}>
<h4>{{title}}</h4>
</a>
<a href="{{url}}">
<p class="username">{{shop_name}}</p>
</a>
<p class="price">{{price}}</p>
</div>
</section>
Here is the JS that grabs the JSON file and tries to make a Vue object:
$.getJSON('../../api/etsy/listings.json')
.then(function(listings){
var listings = new Vue({
el: '#listings',
data: {
title: titles,
images: images,
price: prices,
url: urls
}
});
});
So basically I want the url_fullxfull, title, price, url, shop_name, and shop url to fill in that html and repeat that block of html 42 times. Any suggestions? Thank you!
For HTTP requests, you should use the Vue Resource library:
https://cdnjs.cloudflare.com/ajax/libs/vue-resource/0.1.3/vue-resource.min.js
Then you can write the code like this:
<div v-repeat="etsyData">
...
</div>
var vue = new Vue({
el: '#app',
data: {
apiUrl: "........",
etsyData: {}
},
ready: function(){
this.$http.get(this.apiUrl, function(data, status, request){
this.etsyData = data;
})
}
})
You've put the number 42 in your v-repeat instead of the actual vue property.
If you insist on using jquery instead, then you have to access the vue object from the outside, like this: vue.etsyData = data, or if the data object is in side a component, it will be something like this: vue.$children[0].etsyData = data.