Add dynamic li element and remove the respective one in VUEJS - javascript

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)

Related

AgGrid: multiline header, each line has different style

I am trying to make the headers of my AgGrid table have 2 lines: the first line is the name, the 2nd line is the unit. I want the 2nd line's font size to be smaller than the 1st one.
I've tried to search for this but could not find the answer. I found this blog about styling the header and followed this answer to make my headers be in 2 lines. But none of them shows how to show 2-line headers and style each line independently. Appreciate any help.
I did this in my Markdown Editor using a Custom Header and having each line as as separate div.
The code for my custom header is here: https://github.com/eviltester/grid-table-editor/blob/master/customHeader.js
The basic HTML for the header was:
this.eGui.innerHTML = `
<div class="customHeaderTop">
<div class="customFilterMenuButton">
<i class="ag-icon ag-icon-filter"></i>
</div>
<div class="customHeaderLabel">${this.agParams.displayName}</div>
</div>
<div class="headerbuttons">
<span title="add left">[<+]</span>
<span title="rename">[~]</span>
<span title="delete">[x]</span>
<span title="duplicate">[+=]</span>
<span title="add right">[+>]</span>
</div>
`;
Custom Header Components are described here:
https://www.ag-grid.com/javascript-data-grid/component-header/
It is also possible to add a header template if rendering requirements are simple.
This is covered in the AG Grid Blog post https://blog.ag-grid.com/adding-hyperlinks-to-the-grid/
{
minWidth: 150,
field: 'athlete',
headerComponentParams: {
template:
'<div class="ag-cell-label-container" role="presentation">' +
' <span ref="eMenu" class="ag-header-icon ag-header-cell-menu-button"></span>' +
' <div ref="eLabel" class="ag-header-cell-label" role="presentation">' +
' <span ref="eSortOrder" class="ag-header-icon ag-sort-order" ></span>' +
' <span ref="eSortAsc" class="ag-header-icon ag-sort-ascending-icon" ></span>' +
' <span ref="eSortDesc" class="ag-header-icon ag-sort-descending-icon" ></span>' +
' <span ref="eSortNone" class="ag-header-icon ag-sort-none-icon" ></span>' +
' <span ref="eText" class="ag-header-cell-text" role="columnheader"></span>' +
' <span ref="eFilter" class="ag-header-icon ag-filter-icon"></span>' +
' </div>' +
'</div>'
},
}

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 :)

Remembering image position on upload inside v-for loop

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

append() fail to make boostrap component works

This drive me crazy, i've this simple html bootstrap-gentelella template that works almost in every page of the site that im developing, the html is so simple:
(this code make the part in the class "x_content" visible or not visible by clicking the "collapse-link" class in the "a" tag)
<div class="x_panel">
<ul class="nav navbar-right panel_toolbox">
<li>
<a class="collapse-link freccia_feed">Replies
<i class="fa fa-chevron-up"></i>
</a>
</li>
</ul>
<div class="x_content" style="display: none;">
<div class="input-group col-md-12 col-sm-12 col-xs-12">
<input data-role="tagsinput" id="risposta_'+j+'_D_'+element+'" class="form-control risposta_domanda_'+element+'" name="reply" value="" placeholder="Insert one solution" type="text">
<span class="input-group-btn">
<button id="elimina_risp_'+j+'_D_'+element+'" class="btn btn-danger glyphicon glyphicon-trash" > </button>
</span>
</div>
</div>
</div>
be carefull that the part like id="risposta_'+j+'_D_'+element+'" have no sense in this static part, and rendered as is it, just for example, I use that in the jQuery function that fail to make it works!
here:
$("#domanda_"+element).append(
'<div class="x_panel">'+
'<ul class="nav navbar-right panel_toolbox">'+
'<li>'+
'<a class="collapse-link freccia_feed" >Replies'+
'<i class="fa fa-chevron-up"></i>'+
'</a></li></ul>'+
'<div class="x_content" style="display: none;">'+
'<div class="input-group col-md-12 col-sm-12 col-xs-12">'+
'<input data-role="tagsinput" id="risposta_'+j+'_D_'+element+'" class="form-control risposta_domanda_'+element+'" name="reply"'+
'value="" placeholder="Insert one solution" type="text">'+
'<span class="input-group-btn"><button id="elimina_risp_'+j+'_D_'+element+'" class="btn btn-danger glyphicon glyphicon-trash" >'+
'</button></span>'+
'</div></div></div>');
I've tried many options to make this string works inside append() and the only one that seems working it to wrap the whole string with single ' using double " for ids class etc. and then inject javascript variable with single ' and +. Same thing for new line.
I even try to escape the whole string with online escape tools like https://www.freeformatter.com/javascript-escape.html
but still the same result, the component not works if is appended!
the problem is in the "inizialization" of the class ".collapse-link" by gentelella js.
So i move the function under my "div" generation function's.
I even add a "unbind()" func to resolve the problem that "inizialization" can toggle even the allready rendered div making them open anc closing several time...
thats the code if someone can find it usefull
cheers
$(".collapse-link").unbind("click");
$(".collapse-link").on("click", function() {
var a = $(this).closest(".x_panel")
, b = $(this).find("i")
, c = a.find(".x_content");
a.attr("style") ? c.slideToggle(200, function() {
a.removeAttr("style")
}) : (c.slideToggle(200),
a.css("height", "auto")),
b.toggleClass("fa-chevron-up fa-chevron-down")
});

background binding with knockout

I have the following knockout bindings...
<ul class="list-group" data-bind="foreach: $parent.levels">
<li class="list-group-item">
<img alt="level" class="pic" data-bind="attr:{src: '../../Content/images/levels/' + $index() + '.png'}" />
<button class="btn btn-default piclabels" data-bind="click:$parent.startingLevel.bind($parent,$index()),text:$data,css:{active:$parent.startingLevel() == $index()}"></button>
</li>
</ul>
I want to remove the img tag and instead apply background images to the button. I have tried multiple examples all over the web, including from knockout, but I haven't been able to get it to work.
data-bind="style: {background: 'url('../../Content/images/levels/' + $index() + '.png')' repeat-none left}"
What am I doing wrong?
When using the style binding, each style needs to return a string for the whole value. So if you are using single quotes such as in a url you need to escape them using backslash \. Instead of repeat-none, I think you meant to use no-repeat.
data-bind="style: {background: 'url(\'../../Content/images/levels/' + $index() + '.png\') no-repeat left' }"
JsFiddle

Categories

Resources