Reputation: 271
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.
Upvotes: 0
Views: 618
Reputation: 8329
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>
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.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.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).
Upvotes: 1