Can't remove item from dynamically generated list - vue.js

I'm having trouble with a function that I've created using scotch.io's VueJS guide. It's supposed to remove a function from the list on click, (triggering a view update) but I keep getting this console error:
[Vue warn]: Property or method "$index" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
(found in root instance)
The guide doesn't say to declare anything in the data option, what am I missing?
Here's the HTML:
<a href="#" class="list-group-item" v-for="event in events">
<h4 class="list-group-item-heading">
<i class="glyphicon glyphicon-bullhorn"></i>
{{event.name}}
</h4>
<h5>
<i class="glyphicon glyphicon-calendar" v-if="event.date"></i>
{{event.date}}
</h5>
<p class="list-group-item-next" v-if="event.description">{{event.description}}</p>
<button class="btn btn-xs btn-danger" v-on:click="deleteEvent($index)">Delete Event</button>
</a>
And the relevant JS:
new Vue({
...
methods: {
...
deleteEvent: function(index) {
if (confirm("Are you sure you want to delete this event?")) {
this.events.$remove(index);
}
}
}
});
There's already been a couple of cases where I've had to swap out deprecated directives that the guide uses, (v-repeat, v-on="click", etc) is the problem something similar?

The guide you are following is slightly outdated.
In Vue 2.0, using the index requires a little change in the syntax:
<a href="#" class="list-group-item" v-for="(event, index) in events">
<!-- You have to ask for it: ^^^^^^^^^^^^^^ -->
<button class="btn btn-xs btn-danger" v-on:click="deleteEvent(index)">
<!-- Then use it the way you named it: ^^^^^ -->
Delete Event
</button>
</a>

Related

Cannot execute scoped slot and function in the same event Vue

I have the following code which uses this VueTailwind package:
<t-dropdown>
<div
slot="trigger"
slot-scope="{mousedownHandler, focusHandler, blurHandler, keydownHandler}"
>
<button
id="reseller-menu"
aria-label="User menu"
aria-haspopup="true"
#mousedown="mousedownHandler"
#focus="focusHandler"
#blur="blurHandler"
#keydown="keydownHandler"
>
{{ $page.props.auth.user.reseller.name }}
<icon icon="chevron-down" class-name="ml-2" />
</button>
</div>
<div slot-scope="{ blurHandler }">
<span v-for="user in users" :key="reseller.id" role="menuitem" class="block px-6 cursor-pointer py-2 hover:bg-indigo-500 hover:text-white"
#click="changeUser(user.id); blurHandler">{{ user.name }}</span>
</div>
</t-dropdown>
However, the blurHandler is not executed whenever the changeUser(user.id) method (a method in the parent component which seems to execute fine) is added to the #click event. The only way I was able to solve this issue was to use two different events such as the following:
<span v-for="user in users" :key="reseller.id" role="menuitem" class="block px-6 cursor-pointer py-2 hover:bg-indigo-500 hover:text-white"
#click="changeUser(user.id)" #mouseup="blurHandler">{{ user.name }}</span>
How can I use both in the same event since this doesn't seem to work in this case?
When the v-on value is a function reference, the template compiler transforms it into a function call, passing the event argument:
<button #click="functionRef">
<!-- ...is transformed into: -->
<button #click="functionRef($event)">
But when the v-on value is an expression, the template compiler wraps it in a function:
<button #click="onClick(); functionRef">
<!-- ...is transformed into: -->
<button #click="() => { onClick(); functionRef; }">
Notice functionRef; is not a function call, and effectively does nothing. To actually invoke the function in that expression, add the parentheses to make it a call:
<button #click="onClick(); functionRef()">
So your markup should be:
<div slot-scope="{ blurHandler }">
<span v-for="user in users" ⋯ 👇
#click="changeUser(user.id); blurHandler()">
{{ user.name }}
</span>
</div>
Also note slot-scope has been deprecated for v-slot, as of 2.6.0.

Nuxt.js/Vue.js dynamic images is not working

I'm getting some data from an API that contains an image and some other information. Now there's a problem in Nuxt js or maybe I'm wrong. Whenever I supply the path to the image in the :src it just doesn't work.
Here's my code:
<div v-for="(project, index) in projects" :key="project.p_id" class="swiper-slide">
<div :id="`index_${index}`" class="slide_wrapper">
<div class="background">
<img :src="getImgUrl(project.p_img_path)" alt="project cover image" />
</div>
<div class="details">
<div>
<div class="left">
<h2 style="color: black !impor tant">{{ project.p_label }}</h2>
<small>{{ project.p_date }}</small>
</div>
<div class="right">
<nuxt-link class="btn btn-secondary" to="/" #click="readMore">
<i class="fas fa-ellipsis-h"></i>
</nuxt-link>
</div>
</div>
</div>
</div>
</div>
script:
props: ['projects'],
methods: {
readMore() {},
getImgUrl(path) {
return '../../../' + path
},
},
Last thing, whenever I use required required('./assets/'+image.jpg') nuxt.js crushes in compilation always stops at 69%. I also tried required.context but it didn't work as well.
Any help will be appreciated. Thanks in advance.
In your template, change:
<img :src="getImgUrl(project.p_img_path)" alt="project cover image">
To:
<img :src="require(`../assets/${project.p_img_path}`)" alt="project cover image">
You shouldn’t need a method to return the path as a string, just use a template literal as above.
Ps. This assumes project.p_img_path = img/project_img/filename.jpg, so adjust as necessary.
The solution is that I had to put all the images inside the assets folder directly. Thank you all for your time.

v-on:click not working - dynamically added html element

I am trying to get all images for a category using Vue
<div class="col-md-12 col-sm-2 p-2">
<a v-on:click="onCategoryManageImageClick($event)" data-target="#location-
category-images">
</span>
</a>
</div>
So the event onCategoryManageImageClick ($event) does not work, if I am adding a html block and then click on get image button.
this is index.js
methods:{
onImagesTabClick(){
this.$root.$emit('activated-tab:location-images');
},
onCategoriesTabClick(){
window.j1App.eventBus.$emit("j1-location-image-list:shown");
},
onCategoryManageImageClick: function(event) {console.log('working event..');
event.preventDefault();
window.j1App.eventBus.$emit("j1-location-category-image-
list:shown",event.currentTarget.id);
}
}
So basically it need to to work like we do in jQuery
$(document).on('click',function{
})
So it works either page load or if adding any new html element on DOM. same I want in Vue.
You cannot alter the Vue template outside of Vue. That won't work. Vue compiles the template once when starting up and adds the event listeners to the rendered elements. If you add elements afterwards, Vue will not know about them.
The correct way of doing this would be to add those new elements in Vue.
<div
class="col-md-12 col-sm-2 p-2"
v-for="item in items"
:key="item.id"
>
<a
v-on:click="onCategoryManageImageClick($event, item)"
data-target="#location-category-images"
>
</a>
</div>
See https://v2.vuejs.org/v2/guide/list.html for documentation. In this case you need the items array variable in data and add more array elements to it, if you need more links.
Try raplacing your a tag with p
<div class="col-md-12 col-sm-2 p-2">
<p v-on:click="onCategoryManageImageClick" data-target="#location-
category-images">
</p>
</div>

How to remove item from list in VUE?

I have the container which consist of different div. I want to remove specific ones on click. My code (by example from vue page) not working and I cant figure why... May be there is some suggestions?
<div class="m-t-15">
<div v-for="(tag, index) in $parent.post.tags" v-on:remove="$parent.post.tags.splice(index, 1)" class="btn-group btn-group-sm m-b-5">
<button type="button" class="btn btn-default" disabled="disabled">#{{ tag.name }}</button>
<button type="button" class="btn btn-default" v-on:click="$emit('remove')">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
You shouldn't need to access parent's data like that. Mutating parent's data is not a good practice. Just pass props down, and emit event back to the parent component.
Child components emit remove event:
<button #click="$emit('remove', i)">...</button>
The parent component:
<child :list="list" #remove="remove"></child>
remove (i) {
this.list.splice(i, 1)
}
Please see the working example here: http://codepen.io/CodinCat/pen/PmYNBb?editors=1010

Can I specify multiple data targets for Twitter Bootstrap collapse?

I'd like to target two divs for expand when clicking on a single trigger? Is that possible?
You can simply add all the ids separated by commas in data-target:
<button type="button" data-toggle="collapse" data-target="#demo,#demo1,#demo2">
Hide them all
</button>
Use the same class for both div's and set your data-target according this. Give your div's also the same parent (can also be a class) and set data-parent according this.
<button type="button" data-parent="#wrap" data-toggle="collapse" data-target=".demo">
simple collapsible
</button>
<div id="wrap">
<div class="demo collapse">
test1
</div>
<div class="demo collapse">
test1
</div>
</div>
From the Bootstrap 3 documentation:
The data-target attribute accepts a CSS selector to apply the collapse to.
Therefore you can use a comma-separated list of id's, class selector etc. for the data-target attribute value:
<button class="btn btn-primary"
type="button"
data-toggle="collapse"
data-target="#target1,#target2,#target3"
aria-expanded="false"
aria-controls="target1,target2,target3">
You can see an extensive list of valid CSS selectors on the w3schools website.
If you want to hide one element and show another (like the bootstrap accordion but without a panel) you can add multiple targets but also add the class 'in' to have one element expanded on load!
<div class="collapse text-center clearfix in" id="section1">
<h1>This is section 1</h1>
<p>Are you excited about toggling?</p>
</div>
<div class="collapse text-center clearfix alert-warning" id="section2">
<h1>Boo!!</h1>
<p>This is a new sentence</p>
</div>
<button class="btn btn-block btn-primary" data-toggle="collapse" data-target="#section1,#section2">Toggle</button>
Live demo here
There is a solution in Bootstrap 4:
Bootstrap 4 documentation: Multiple targets
The least you need is:
data-toggle="collapse" data-target=".multi-collapse" for the toggle
button
class="collapse multi-collapse" for each element you need to
toggle
(While multiple ids in data-target indeed don't work).
The data-target answer did not work for me. However you can use JavaScript to do this.
Make your button call some JavaScript like:
$('.collapse-class').collapse('toggle')
See: https://getbootstrap.com/javascript/#via-javascript-3.
Bootstrap 4 uses document.querySelector instead of document.querySelectorAll. If this changes, then everything works.
In Bootstrap 4 using the same class for each respective div seemed to work over using id.
<button type="button" class="btn" data-toggle="collapse" data-target=".collapse-group">
Reveal Items</button>
<div class="row">
<h3>Visible Row div 1</h3>
<div class="collapse-group collapse">
<p>hidden item</p>
</div>
<h3>div 2</h3>
<div class="collapse-group collapse">
<p>hidden item 2</p>
</div>
</div>
I faced the same problem but bootstrap won't let data-toggle="tab" beside data-toggle="collapsed" so my problem was like this.
I have:
<a type="button" class="btn btn-default btn-lg btn-block " href="#ld-tab-pane-eye" aria-expanded="false" aria-controls="ld-tab-pane-eye" role="tab" data-toggle="tab" aria-haspopup="true" aria-expanded="false" style=" border: 0px ;"> </a>
and this was switching tabs:
<button type="button" class="navbar-toggle collapsed nav-trigger style-mobile" data-toggle="collapse" data-target="#main-header-collapse" aria-expanded="false" data-changeclassnames='{ "html": "mobile-nav-activated overflow-hidden" }'>
</button>
But this one closes the modal because the switch tab button was in the modal.
To solve the problem I add id="popout"(to first button) and id="popoutTrigger" (to secend button).
And this script (jQuery):
$( "#popout" ).click(function() {
$( "#popoutTrigger" ).trigger( "click" );
});
When the user clicked the switch button in the modal, after switching modal will close.
This a view of what I've done.
I hope my solution will help.