Vue make each v-for have own version of variable - javascript

i am looping through an array displaying songs I have uploaded into firebase. I am giving the user a button to edit the name of the song if they press the edit button. When button is pressed it show to edit details, however, except of only the one object expanding all of them expand to edit. How can I give each object its own version of the showForm Bool thanks.
Displaying songs:
<div v-for="song in watchSongs" :key="song.docID">
<div class="mt-[10px] border-solid border-2 border-gray-400 rounded-lg p-[5px] min-h-[40px]">
<p class="font-bold float-left">{{song.modifiedName}}</p>
<img #click.prevent="showForm = !showForm" src="#/assets/edit.png" alt="" class="w-[20px] float-right hover:cursor-pointer">
<img src="#/assets/close2.png" alt="" class="w-[20px] float-right hover:cursor-pointer">
<div v-if="this.showForm" class="pt-[30px]">
<p>song title</p>
<input type="text" placeholder="Enter Song Title" class="w-[100%] h-[30px] pl-[5px] mt-[10px] bg-transparent border-[1px] border-solid border-gray-300">
<p>Genre</p>
<input type="text" placeholder="Enter genre" class="w-[100%] h-[30px] pl-[5px] mt-[10px] bg-transparent border-[1px] border-solid border-gray-300">
<div class="flex mt-[20px] mb-[10px]">
<button class="bg-green-500 rounded-md w-[70px] mr-[5px]">Submit</button>
<button class="bg-gray-400 rounded-md w-[70px]">Go back</button>
</div>
</div>
</div>
The data:
export default {
name:"AppUploadDetails",
props: ['songs'],
data(){
return{
showForm:false,
}
},
computed:{
watchSongs(){
return this.songs;
}
}
}

Fixed by changed the v-if to v-if="song.showForm" and the click to #click.prevent="song.showForm"

Use an object to store your loop items, with the key being the docID.
Something like this:
showForm: {}
click.prevent="showForm[song.docID] = !showForm[song.docID]

Related

Uploaded image in angular 7 not displayed just after upload

I have written the below code which is working, there is no compilation error. I am successfully getting the uploaded images printed in the console. But just after uploading the image, its not visible in the page. I need to click anywhere on the screen ,then the images get previewed in the screen.
onFileChange(event) {
if (event.target.files && event.target.files[0]) {
var filesAmount = event.target.files.length;
for (let i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.readAsDataURL(event.target.files[i]);
reader.onload = (event: any) => {
this.images.push(event.target.result);
};
}
}
}
<form [formGroup]="formGroup" (ngSubmit)="submit()">
<section>
<h3 class="fs-20 fw-600 text-color9 mb-30">
Step 4: Sample information
</h3>
<div class="samples d-flex flex-wrap mb-5">
<div class="sample-item mb-3 mb-lg-0">
<div
class="upload-box rounded-4 bg-white position-relative d-flex justify-content-center align-items-center flex-column overflow-hidden"
>
<input
id="file"
type="file"
class="form-control"
accept="image/*"
(change)="onFileChange($event)"
/>
<i class="icon-plus fs-36 text-color4 mb-2"></i>
<h6 class="fs-18 fw-500 text-color4 mb-0">Upload image</h6>
</div>
</div>
<div class="sample-item mb-3 mb-lg-0">
<div class="image-box">
<img class="rounded-4" *ngFor="let url of images" [src]="url" />
<br />
</div>
</div>
</div>
//other formgoup inputs will be written here
<div class="action-button pb-3">
<hr />
<div class="text-end">
<button
type="button"
class="btn btn-sm btn-primary-outline me-3"
routerLink="/order/create-order"
[queryParams]="{ id: orderObject?.orderID }"
>
Back
</button>
<button type="submit" class="btn btn-sm btn-primary">
Continue
</button>
</div>
</div>
</section>
</form>
Every time I click choose file in the this.image the images get inserted. If I try to runconsole.log(this.images) it also gets printed . But its not immediately rendered in the screen by this array this.images via *ngFor
When this ts code is run in https://stackblitz.com/edit/angular-file-upload-preview?file=app%2Fapp.component.ts its running fine. Just after choosing file the image get visible in the screen.
Please help me to know what is the reason behind such behavior.
You might need to run the angular cycle again. try
constructor(
private cdr: ChangeDetectorRef
) {}
reader.onload = (event: any) => {
this.images.push(event.target.result);
this.cdr.detectChanges();
};

loading foreign key data in drop down select name too slow

I'm trying to show foreign key data as a drop down list, but we have a big data, the problem is it takes too long to load page that has the drop down field with the foreign key, is there a way to load it part by part?
here is my models.py
class Vistor(models.Model):
admin = models.ForeignKey(User,on_delete=models.PROTECT,default=1)
full_name = models.CharField(max_length=150,verbose_name=_('full name'))
dob = models.DateField(max_length=14,verbose_name=_('dob'))
city = models.ForeignKey(City,on_delete=models.CASCADE,verbose_name=_('city'))
class Meta:
constraints = [
models.UniqueConstraint(fields=['full_name','dob','city'],name='full_information')
]
def __str__(self):
return f'{self.full_name} - {self.city} - {self.dob}'
and here is my views.py
def add_new_post(request):
...
context = {
'form':form,
'room_number':room_number,
'cities':City.objects.all(),
'all_guests':Vistor.objects.all().order_by('-pk'), #the problem is here, has a big data
}
return render(request,'booking/add_booking.html',context)
and here is my templates
<div class="grid md:grid-cols-10 md:gap-5 child_formset_row" id="guests_no-${form_no}">
<div class="col-span-5 groupinput relative bglightpurple mt-2 rounded-xl">
<label class="text-white absolute top-1 mt-1 mr-2 text-xs">{% trans "full information" %}</label>
<select name="guestinfo-0" id="guestinfo-0" class="visitors w-full pr-2 pt-6 pb-1 bg-transparent focus:outline-none text-white">
<option value="-----">------</option>
{% for c in all_guests %}
<option value="{{ c.full_name }} - {{c.city}} - {{c.dob | date:'Y-m-d'}}">{{ c.full_name }} - {{c.city}} - {{c.dob | date:'Y-m-d'}}</option>
{% endfor %}
</select>
</div>
<div class="col-span-4 groupinput relative bglightpurple mt-2 rounded-xl">
<label class="text-white absolute top-1 mt-1 mr-2 text-xs">{% trans "reason" %}</label>
<input type="text" name="reason-0" id="reason-0" value="" required class="w-full pr-2 pb-1 pt-6 bg-transparent focus:outline-none text-white">
</div>
<button type='button' class="col-span-1 flex items-center justify-center groupinput relative bglightpurple mt-2 rounded-xl" onclick="remove_form(this,${form_no})"><i class="text-red-600 far fa-trash-alt"></i></button>
</div>
is there a way to load it part by part please ?
thank you so much for your helps ..
You can use django-autocomplete-light along with leveraging Django forms to display that element.
This gives a searchable as well as scrollable dropdown that loads your data with a pagination type of concept.

Dynamically add new rows to the table

I am creating a table with alpinejs, it should returns new row if someone hit "click to add" link
I have this code:
<div class="mt-2" x-data="services()">
<tbody class="bg-gray-200" x-model="newService" x-show="services.length">
<template x-for="service in services" :key="service.id">
<td x-text="services.length" >
<a #click="addService()">Click to add more</a>
<script>
function services() {
return {
services: [],
,
newService: '',
addService() {
this.services.push({
id: this.services.length + 1,
body: this.newService,
completed: false
});
this.newService = '';
},
deleteService(service){
let position = this.services.indexOf(service);
this.services.splice(position, 1);
}
}
}
</script>
but instead of returning a new row it returns 23 rows at ones!!
how can I fix that?
Adding to the existing answer, here is a simple working example.
<link href="https://unpkg.com/tailwindcss#^1.0/dist/tailwind.min.css" rel="stylesheet">
<script src="//unpkg.com/alpinejs" defer></script>
<div class="mt-4 flex flex-col max-w-lg mx-auto" x-data="services()">
<div class="flex space-x-2">
<input type="text" x-model="newService" class="px-2 py-1 border flex-1 rounded" placeholder="Service">
<button class="border bg-blue-600 hover:bg-blue-700 text-white rounded px-4 py-1" #click="addService()">Add
service</button>
</div>
<div x-show="services.length">
<div class="rounded border mt-4 text-xs">
<table class="w-full">
<thead>
<tr>
<th class="bg-gray-100 font-normal text-gray-500 uppercase py-2">Services</th>
</tr>
</thead>
<tbody>
<template x-for="service in services" :key="service.id">
<tr class="border-t">
<td class="flex justify-between items-center px-4 py-1">
<span x-text="service.body"></span>
<button class="text-sm uppercase text-red-500 px-2 py-1 rounded hover:bg-red-100"
#click="deleteService(service.id)">x</button>
</td>
</template>
</tbody>
</table>
</div>
<button class="text-xs w-full mt-2 bg-red-100 text-red-400 px-2 py-2 rounded hover:bg-red-200" #click="services = []">Delete
All</button>
</div>
</div>
<script>
function services() {
return {
services: [{
id: 1,
body: 'Service 1',
completed: false
},
{
id: 2,
body: 'Service 2',
completed: false
}
],
newService: '',
addService() {
if (this.newService.length < 1) return;
this.services.push({
id: Date.now(),
body: this.newService,
completed: false
});
this.newService = '';
},
deleteService(serviceId) {
let position = this.services.findIndex(el => el.id == serviceId);
this.services.splice(position, 1);
}
}
}
</script>
With limited code and without a working example it is bit hard to give a concrete answer. By looking at the code, I think you are getting the existing number of rows in your table body.
addService() {
this.services.push({
id: this.services.length + 1,
body: this.newService,
completed: false
});
this.newService = '';
}
In this method you are selecting this.newService as your body. And looking at your HTML <tbody class="bg-gray-200" x-model="newService" x-show="services.length"> newService is the entire body of the existing table.
So you are getting the existing 23 rows.

modal opening only for the first for loop element?

I have my for loop in Django such as its only opening the modal for the first element and nothing happens for other elements.
This is my HTML file it display all elements in a table with delete button. When clicking delete button a modal is opened but it is opened for the first element only, what should I change in this?
<table>
{% for card in cards %}
<tr class="record">
<td>{{card.number}}</td>
<td>
<button
class="hover:bg-gray-500 duration-500"
id="delete-btn"
>
</button>
<div
class="
fixed
flex
justify-center
items-center
hidden
"
aria-labelledby="modal-title"
aria-modal="true"
id="overlay"
>
............. #some lines of code
<div
class="
bg-gray-50
px-4
py-3
sm:px-6 sm:flex sm:flex-row-reverse
"
>
<a
href="{% url 'p:delete-card' card.id %}"
id="delbutton"
>
<button
type="button"
class="
w-full
inline-flex
justify-center
"
>
Delete
</button>
</a>
</div>
</div>
</div>
</td>
</tr>
{% endfor %}
My js to open the modal on button click
window.addEventListener('DOMContentLoaded',() =>{
const overlay = document.querySelector('#overlay')
const delbtn = document.querySelector('#delete-btn')
const toggleModal = () => {
overlay.classList.toggle('hidden')
overlay.classList.add('flex')
}
delbtn.addEventListener('click',toggleModal)
})
I solved it like this with the help of Data in Django for loop {% for %} not loading for Modal
I changed the id of all the buttons like this and added delete-button class!
<button class="hover:bg-gray-500 duration-500 delete-button" id="delete-btn_{{card.id}}">
</button>
Like this added card.id in overlay too.
My Jquery:
$(".delete-button").click(function() {
var id = $(this).attr("id").split("_")[1]
$(`#overlay_${id}`).show();
});
Every modal should have a different id in the for loop.
You can use something like id="modal{{card.id}}"
Then select that id
Does that help you?

Show individual record on pop up Laravel

I am using a resource controller. All records are displayed on the dashboard. From here, I am trying to show an individual record after I click the show button.
The data is displayed on the pop up but it is the wrong one.
How can I solve this issue?
DashboardController.php
public function index()
{
$frontend = Frontend::orderBy('created_at', 'desc')->paginate(10);
return view ('dashboard')->with('frontends',$frontend);
}
dashboard.blade.php
<button type="submit" class="btn btn-secondary" onclick="showReviewModal()">
<i class="fas fa-eye"></i>
</button>
<div id="modalReview"
class="fixed overflow-x-hidden overflow-y-auto inset-0 flex justify-center items-center z-50 p-6"
style="display: none;">
<div class="relative mx-auto w-auto max-w-2xl">
<div class="bg-white w-full p-12 rounded-lg text-xl">
<span><strong>Review</strong></span>
<br />
#if (count($frontends))
<p class="mt-6 text-justify">{{ $frontend->review }}</p>
#endif
</div>
</div>
</div>
script.js
function showReviewModal() {
$("#modalReview").show();
$("#modalShadow").show();
}
You can consider getting the record id using jQuery/JavaScipt e.g
var id = attr('id')
This is assuming you would have used a data attribute "data-id"
From there, you simply do an Ajax call to the server to call the individual record you want to display in the modal by passing back the record id.
<script>
$(document).ready(function(){
$(this).click(function(){
var id = attr('id')
$.ajax({
type: "GET",
url: "/YOUR_URL/" + id,
dataType: "json",
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function (response) {
//CALL YOUR MODAL HERE AND LOAD IT WITH THE RETURN DATA
}
});
</script>

Categories

Resources