Remembering image position on upload inside v-for loop - javascript

I am having a hard time figuring this one out.
I'm using Vue.js and I'm trying to create some sort of a dashboard where a user would be able to upload up to five images of visitors that are allowed to use some service that said user is providing.
Here is the code:
<div class="row" v-for="(n, i) in 5" :key="n">
<div :id="'popover' + visitor.id + '-' + i" variant="primary">
<div class="card visitor-image">
<b-popover :target="'popover' + visitor.id + '-' + i" triggers="click focus">
<template slot="title">Edit image</template>
<button
v-if="checkImage(i)"
class="btn btn-danger image-btns"
#click="deleteImage(visitor.id, visitor.Photos[i].id)"
>Delete</button>
<p
v-if="uploadProgress < 100 && uploadProgress > 0"
class="progress-text"
>Upload progress: {{ uploadProgress }}%</p>
<label
v-if="!checkImage(i)"
:for="'image-input' + visitor.id + '-' + i"
class="btn btn-primary image-btns"
>Upload</label>
<input
class="profile-image"
:id="'image-input' + visitor.id + '-' + i"
type="file"
:ref="'fileInput' + visitor.id + '-' + i"
style="display: none"
accept="image/gif, image/jpeg, image/png"
placeholder="Upload"
#change="selectFile($event, visitor.id, 'fileInput' + visitor.id + '-' + i)"
>
</b-popover>
<img
class="card-img-top profile-image"
v-if="checkImage(i)"
:src="getImage(i)"
:id="visitor.Photos[i].id"
>
<img class="card-img-top avatar-image" v-else src="../assets/avatar.png">
</div>
</div>
</div>
None of the functions are important here, the only thing that matters is this "v-for" loop I'm using.
As you can see, I'm iterating through all the visitors and their images and I'm binding a key for each one.
What I want to know is, how do I use that key so that once I click on one of the avatar images and upload a photo, that same photo is upload in that exact div?
Right now, wherever I click one of the five divs to upload an image, it will be displayed on the first div even if I click on the last div in the list.
Thanks

I have created the codepen for file upload inside the v-for loop. I have used splice for adding an image at a particular index. Please refer the following codepen for more detail.
codepen - https://codepen.io/anon/pen/XGYoyr

Related

Adding an integer to string

I am trying to add an integer to the card id so that I can delete it when pressing the delete button. Any help?
var variable = '' +
'<div id="card+$num.toString(cnt);" class="card col-3" style="width: 18rem;" style="margin-right=3%; margin-right=3%">' +
' <img src="..." class="card-img-top" alt="..." id="image"+String(cnt)>' +
' <div class="card-body">' +
' <h5 class="card-title" id="title"+String(cnt) contentEditable="true"; >Card title</h5>' +
' <p class="card-text" id="desc"+String(cnt) contentEditable="true">Some quick example text to build on the card title and make up the' +
' bulk of the' +
' card\'s content.</p>' +
' <a href="#" class="btn btn-primary" id="button"+ String(cnt) >Go somewhere</a>' +
' <a href="#" id="btn"+String(cnt) class="close"+String(cnt)>Delete</a>' +
' </div>' +
' </div>' +
'';
$(".create").click(function(){
document.getElementById("lastRow").innerHTML+=variable;
});
$(".close"+String(cnt)).click(function(){
console.log("Doulevw!");
document.getElementById("card"+String(cnt)).hidden=true;
});
There are a few concepts that you have to know when rendering dynamic elements with js.
you have a click listener for your .close button. This listener will never fire because this listener is relevant only for your initial DOM. But your closing button is rendered dynamically, which means that listener not relevant for your button.
Easily solving that by attaching onclick to the button, and creating a function. (example follows)
I inspected your code, you DON'T have to use id mechanism to delete/hide your card element (unless you need to fire POST request), you can use parentNode (example follows)
I made some simple changes to your code:
$(".create").click(function(){
let element = `
<div id="card" class="card col- 3" style="width:18rem;style="margin-right=3%; margin-right=3%"><img src="..." class="card-img-top" alt="..." id="image"+String(cnt)><div class="card-body"><h5 class="card-title" id="title" contentEditable="true">Card title</h5><p class="card-text" id="desc" contentEditable="true">Some quick example text to build on the card title and make up the bulk of the' card\'s content.</p><a href="#" class="btn btn-primary" id="button"+ String(cnt) >Go somewhere</a><a href="#" class="close" onclick='deleteCard(this)'>Delete</a></div></div>`;
document.getElementById("lastRow").innerHTML+=element;
});
function deleteCard(delBtn){
delBtn.parentNode.parentNode.hidden = true
}
Notice for the function I added and the onclick that enables the hiding action.
Here is a codeped link for you to test by your self what I did.
Hope this was helpful, any other questions will be great :)

How can you disable a button if data ID exists in local storage object?

I am trying to prevent multiple votes of the same question on a component when a user clicks yes or no.
I have stored the user's response in local storage into an Object Array. I need to find a way to check if that object ID exists in local storage and thus, disable it so to stop the user voting for the same thing over and over and over again.
I have tried to place a boolean on the button so... [disabled]="disabled", but when the user navigates and returns, the button is active again.
poll-item.component.ts
This is the example of the 'No' vote click event:
VoteNo() {
const newVote = {
id: this.poll.id,
poll_title: this.poll.poll_title,
poll_question: this.poll.poll_question,
yes: this.poll.yes,
no: this.poll.no + 1
}
this.pollsService.updatePoll(this.poll.id, newVote)
.subscribe(
response => {
if (localStorage) {
var userVotes;
if (!localStorage['userVotes']) userVotes = [];
else userVotes = JSON.parse(localStorage['userVotes']);
if (!(userVotes instanceof Array)) userVotes = [];
userVotes.push(newVote);
localStorage.setItem('userVotes', JSON.stringify(userVotes));
}
this.getPolls.emit(response);
}
)
}
poll-item.component.html
<ng-container *ngIf="config">
<ng-container *ngIf="poll">
<span class="poll_header_wrapper">
<div class="poll_icon">
<img src="../../../../assets/img/poll_icon.svg">
</div>
<div class="poll_title">
<h5>{{ poll.poll_title }}</h5>
</div>
</span>
<div class="question_buffer">
<p>
<small>{{ poll.poll_question }}</small>
</p>
</div>
<span class="results">
<p><small>
<h4 *ngFor="let config of config"
[ngStyle]="{'background': 'linear-gradient(to right, #' + config.primary_color.data.hex_code + ' ' + percentage(poll.yes, [ poll.yes + poll.no ]) + '%' + ', #' + config.secondary_color.data.hex_code + ')'}">
<i class="fas fa-thumbs-up"></i> {{ percentage(poll.yes, [ poll.yes + poll.no ]) }} %</h4>
</small></p>
<p><small>
<h4 *ngFor="let config of config"
[ngStyle]="{'background': 'linear-gradient(to right, #' + config.primary_color.data.hex_code + ' ' + percentage(poll.no, [ poll.yes + poll.no ]) + '%' + ', #' + config.secondary_color.data.hex_code + ')'}">
<i class="fas fa-thumbs-down"></i> {{ percentage(poll.no, [ poll.yes + poll.no ]) }} %</h4>
</small>
</p>
</span>
<p class="totals"><small>Total: {{ getTotalVotes(poll.yes, poll.no) }} Votes</small></p>
<div class="voting_buttons">
<button (click)="voteYes(poll)" **[disabled]="disabled"**><i class="fas fa-thumbs-up"></i></button>
<button (click)="VoteNo(poll)" **[disabled]="disabled"**><i class="fas fa-thumbs-down"></i></button>
</div>
</ng-container>
</ng-container>
[disabled]="disabled" - this doesn't work, but could potentially by checking if id in local storage is true. I just don't know the best way to write it.
What I would like to know is how once the request has been sent to local storage, can I then run a check of the local storage array find the IDs that have been voted on and disable them? So the user can't vote yes and no multiple times for the same question.
Has anyone done anything like this before?

Add dynamic li element and remove the respective one in VUEJS

I am new in VUE JS.
I have a form where I want to add multiple media.
So on click of "Add media" button i want to add "li" tag with respective html content in which i have on remove button too.
On click on remove button i want to delete the respective li.
What will be the best way to do this?
Here is what i have done so far
HTML:
<div class="col-md-10">
<button #click="addMediaRow()" class="btn btn-primary" :disabled="mediaRowCount >= 3" type="button">Add Media</button>
<br>
<br>
<ul style="list-style-type: none; padding: 0;" id="project_media_ul">
<li v-for="(row, index) in mediaRowArr">
<span v-html="row.template"></span>
</li>
</ul>
</div>
JS
In data i have declared variable
mediaRowLI: '<a v-on:click="openMediaFileInput"><i class="fa fa-camera fa-2x"></i> \n' +
' <span class="photospan">Add Photo </span></a>\n' +
' or Input Video URL here : <input type="text" class="form-control"\n' +
' placeholder="use embed URL, e.g. www.youtube.com/embed/EXa9ZeqRKl8"\n' +
' name="media_video_url" style=" width: 50%">\n' +
' \n' +
' <i class="fa fa-close"></i>\n' +
'\n' +
' <input multiple type="file" accept=\'image/x-png,image/jpeg\' name="media_images"\n' +
' style="visibility: hidden;">\n' +
''
Methods :
addMediaRow () {
this.mediaRowArr.push({
template: this.mediaRowLI
})
},
removeMediaRow (key) {
this.mediaRowArr.splice(key, 1)
},
Thanks in advance
Note that:
you cannot use v-html to compose template partials, because Vue is
not a string-based templating engine. Instead, components are
preferred as the fundamental unit for UI reuse and composition.
(source)
meaning html raw with v-on:click="removeMediaRow" doesn't work.
As the documentation says, you should create a component instead.
(jsfiddle example here)

How to move span to left with margin auto Css angular 4

Hi I have some issue regarding Css and I have not been able to do it.
how to move those numbers which are highlighted to left with names.
I have tried flex direction margin auto etc but I cannot get desired result.
here is my html code
<section class="favorites">
<div class="category" *ngFor="let category of categoryKeys">
<div class="sub-header">{{category}}</div>
<app-custom-accordion [closeOthers]="true">
<ngb-panel [disabled]="panel.Tests.length === 0" *ngFor="let panel of testSelectionSession.FavoritesByCategory[category]"
id="{{panel.Id}}" [title] = "panel.Name">
<ng-template ngbPanelTitle>
<span class="test-length" style=""> {{ '(' + panel.Tests.length + ')'}}</span>
<div class="action-items">
<span class="icon-set" [ngClass]="{'same-day-2x': isSameDay(panel.Code), 'next-day-2x': isNextDay(panel.Code)}"></span>
<label class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" [name]="panel.Id + '-' + panel.Moniker" [ngModel]="checkAllTestsSelected(panel)"
(ngModelChange)="onPanelCheckboxUpdate($event, panel)" [id]="panel.Id + '-' + panel.Moniker">
<span class="custom-control-indicator"></span>
</label>
</div>
</ng-template>
</ngb-panel>
</app-custom-accordion>
I am trying to move this tag to left
<span class="test-length" style=""> {{ '(' + panel.Tests.length + ')'}}</span>
can someone help me regarding this issue?
The simplest solution will be including
'(' + panel.Tests.length + ')'
in the panel title:
<ngb-panel [disabled]="panel.Tests.length === 0" *ngFor="let panel of testSelectionSession.FavoritesByCategory[category]"
id="{{panel.Id}}" [title] = "panel.Name + '(' + panel.Tests.length + ')'">
The component seriously resembles a table, making contents of a separate column float left seems hard to achieve. Although I'm not familiar with ngb-panel.

Remove owl carousel item

I know that there are some associated questions about it, I tried all solutions and read all documentation, but w/o result.
I am initializing a Owl carousel :
HTML
In HTML, I have 2 items :
<div class="owl-carousel owl-theme all_diplomas">
<div class="item diploma-0">
<div class="content_diplomas">
<a data-fancybox="gallery" href="images/6.jpg"><i
class="material-icons">search</i></a>
<figure><img src="images/6.jpg" alt=""></figure>
</div>
<button class="waves-effect delete-diploma waves-blue diploma-0" type="button"><span>x</span> </button>
</div>
<div class="item">
<div class="add_diplomas">
<div class="item_add_diplomas">
<span class="plus_add">+</span>
<span class="txt_btn">Add diploma<br></span>
<input id="generateInputsForDiplomas">
</div>
</div>
</div>
</div>
JS :
$(".all_diplomas").owlCarousel({
loop: true,
margin: 15,
responsive: {
1000: {
items: 4
},
1200: {
items: 2
}
},
});
Next, after my script initialization :
$('input#generateInputsForDiplomas').on('click',function() {
var template = '<div class="item diploma-' + index + '"> <div class="content_diplomas"> <a class="diploma-' + index + '" data-fancybox="gallery" href="images/3.jpg"><i class="material-icons">search</i></a>' +
'<figure><img src="images/3.jpg" class="addedDiplomaInput diploma-' + index + '"alt=""></figure> </div> </div>'
+ '<button class="waves-effect delete-diploma waves-blue ' + classes + '" type="button"><span>x</span> </button>';
var newEl= $('.all_diplomas').trigger('add.owl.carousel', [template, 33]).trigger('refresh.owl.carousel');
});
Code above just adds a block of owl-item with one image and some id-s
and classes.
Then, it appends this template to position 33 and refreshes the
carousel
Them, each element has a delete button associated to owl-item class
$(document).on('click', 'button.delete-diploma',function() {
$(".all_diplomas").trigger('remove.owl.carousel', 33).trigger('refresh.owl.carousel');
});
That's the thing. When adding an element, from documentation, I am setting the position for this element explicitly - like 33. But when I am calling the button that is responsable to remove item with position 33, it deletes entire slider, or sometimes unexpected behavior.
The reason why I'm calling position explicitly, because I need to know each item's index, because when calling delete button, to know item with which position to delete. Documentation offers callbacks that has this information, but not for "add" event.
How can I lifehack that problem? I want to add n-items to carousel, and each this block with image to has it's own delete button. So, when calling this button, it will delete that element and refresh the Owl. I tried with pure jQuery to delete parents and so on... but Owl generates some other classes, and because of it, item is deleted, but empty spaces in slider remains.

Categories

Resources