VueJS mouseover in for loop - for-loop

I have a for that will create a component for each index.
In this component, I have a child div containing edit, add, minus buttons.
I would like it to be displayed on the component mouseover.
How do I achieve this dynamically without having to play with indexes ?
Thank you kindly.

Post component
<template>
<div v-on:mouseleave.native="showOperations = false"
v-on:mouseover.native="showOperations = true">
<!-- post data -->
<div v-if="showOperations">
<!-- operations -->
</div>
</div>
</template>
<script>
export default {
...
data () {
return {
showOperations: false
}
},
...
</script>
List of post
<post v-for="post in posts"
:key="post.id"
:post="post">
</post>
This pattern works for me and I think it works for you as well

Related

how to pass slot/data to inertia layout component

How do I pass a slot or a prop to a layout component in inertia?
For example, heres a ForgotPassword component:
<template>
<slot name="title">Forgot Password</slot>
Forgot pw stuff goes here...
</template>
<script>
import CardLayout from "#/Layouts/CardLayout";
export default {
layout: CardLayout,
}
Here is the CardLayout component:
<template>
<h1>{{ $slots.title }}</h1>
<slot/>
</template>
Nothing shows up inside the h1 tag...
Adding this here as the solution above does not work. You can pass data to the Layout component by setting a prop value
layout: (h, page) => h(Layout, { somePropDataDefinedInLayout: value }, () => page)
// CardLayout
<template>
<h1><slot name="title" /></h1>
<slot />
</template>
// ForgotPassword
<template>
<template #title>Forgot Password</template>
Forgot pw stuff goes here...
</template>

2 way binding with Vue3 Inline template (using slots) in laravel blade template files

In Vue3, inline-templates were depreciated and now slots are used. Is it possible to have 2-way binding of variables for Vuejs components written in blade templates?
I want to have 2-way binding for Vue components that's written inline with blade templates. Although I know I can pass data like <example-component name="Hello World"> It is a ton of work to add props everywhere.
Vue recommends using slots as a inline-template replacement since it got removed in v3, however, that documentation makes no sense. I've got the components displayed using the code below. It's a dead simple text field + paragraph to display the name.
home.blade.php (Removed unnecessary HTML for brevity)
<div>
<h1>Dashboard</h1>
<example-component>
<div class="container">
<input v-model="name" placeholder="Change Name"/>
<p> Name is #{{ name }} </p>
</div>
</example-component>
</div>
example-component.vue
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
name: 'hi',
}
}
}
</script>
Unfortunately, this does not work, the name doesn't start as 'hi' and doesn't update when changing the textfield. When I try something like <slot :name=name></slot>. Which I believe would pass the name into the slots section, the component gets rendered for a second before disappearing.
Is having 2-way binding with vue variables in blade templates even possible? Any help is appreciated.
Vue: 3.0.5
Laravel: 8.29.0
Is there a reason you're storing the data in the child component? The reactivity design works by passing props down and emitting events up, even though (unfortunately) the reactivity is not maintained when passing a variable up to the parent component. Seems a little counter intuitive, but I might be missing something in what you're trying to create.
It will, however, work if you put the data into the app instead of the component.
// app
const app = Vue.createApp({
data() {
return {
name: 'hi',
}
}
})
// component
app.component('example-component', {
template: `
<div>
<slot></slot>
</div>`,
})
app.mount("#app");
<script src="https://unpkg.com/vue#3.0.5/dist/vue.global.prod.js"></script>
<div id="app">
<h1>Dashboard</h1>
<example-component>
<div class="container">
<input v-model="name" placeholder="Change Name"/>
<p> Name is #{{ name }} </p>
</div>
</example-component>
</div>
<!--

Button that shows modal for each b-table row

Im using laravel, vue, and bootstrap-vue.
I have created a vue component that displays a table of elements (subnets in this example).
For each of them I show a component (modal_edit-subnet) thats should open a modal that allows to edit the data of the element of the related row.
The problem is that it shows modals for all of the table elements. For example, if the table has 3 rows, it shows 3 modals (after closing one it shows the next). Each of the modals with the data of each of the rows.
I've tried to add "key"s but no success.
What am i doing wrong?
Thanks!
Component that shows the table
<template>
<div>
<b-card class="text-center">
<b-table small striped hover :items="data_subnets" :fields="fields" :tbody-tr-class="rowClass">
<template slot="[ip_address]" slot-scope="data_subnets">
<b>{{ long2ip(data_subnets.item.ip_address) }}</b>
</template>
<template slot="[actions]" slot-scope="data_subnets">
v-on:deleteSubnet="deleteSubnet"></modal_delete-subnet>
<modal_edit-subnet :key="'modal_edit_subnet' + data_subnets.item.id" :subnet="data_subnets.item" v-on:editSubnet="editSubnet"></modal_edit-subnet>
</template>
</b-table>
</b-card>
</div>
</template>
Modal modal_edit-subnet
<template>
<div>
<b-button size="sm" v-b-modal.modal-edit-subnet>Edit</b-button>
<b-modal
id="modal-edit-subnet"
ref="modal"
title="Edit subnet"
#ok="handleOk"
>
This is subnet {{data_subnet.id}}
</b-modal>
</div>
</template>
The problem is that:
You're rendering a modal for each row of the table and;
Reading the docs, it seems like the modal is triggered by the id, and your b-modal id is not dynamic depending on the row.
How to fix it:
Use just one modal on the b-table level
Dynamically inject id into your modal_edit-subnet component:
<template>
<div>
<b-button size="sm" v-b-modal[id]>Edit</b-button>
<b-modal
:id="id"
ref="modal"
title="Edit subnet"
#ok="handleOk"
>
This is subnet {{data_subnet.id}}
</b-modal>
</div>
</template>
<script>
export default {
props: {
id: {
type: String | Number
}
}
}
</script>
Use v-model (this is the way I would do it)
<template>
<div>
<b-button size="sm" #click="show = true">Edit</b-button>
<b-modal
v-model="show"
ref="modal"
title="Edit subnet"
#ok="handleOk"
>
This is subnet {{data_subnet.id}}
</b-modal>
</div>
</template>
<script>
export default {
data() {
return {
show: false
}
}
}
</script>

Display data in a Vue component with ajax

I seem to be misunderstanding how to pass data to a Vue.js component with an ajax call.
My understanding of how this should work:
I need to create an empty object called campaigns in the data section of my component.
Then call method "fetchCampaigns" on page ready to replace the data object.
fetchCampaign method completes an AJAX call and inside of the success callback use this.$set('campaigns', campaigns) to replace the empty campaign object with the newly returned campaign object
Use v-for on the template to iterate through the campaign object and access values with #{{campaign.type}}
My html (I am use vue router, vue resource and laravel blade) :
<router-view></router-view>
<template id="campaignBlock" v-for="campaign in campaigns">
<div class="row">
<div class="block">
<div class="block-title">
<h2>Type: <em>#{{campaign.id}}</em></h2>
</div>
<div class="row"><!-- Grid Content -->
<div class="hidden-sm hidden-xs col-md-4 col-lg-4">
<h2 class="sub-header">#{{campaign.title}}</h2>
</div>
</div>
</div><!-- END Grid Content -->
</template>
Vue component
Vue.component('app-page', {
template: '#campaignBlock',
data: function() {
return{
campaigns: []
}
},
ready: function () {
this.fetchCampaigns();
},
methods: {
fetchCampaigns: function () {
var campaigns = [];
this.$http.get('/retention/getCampaigns')
.success(function (campaigns) {
this.$set('campaigns', campaigns);
})
.error(function (err) {
campaigns.log(err);
});
},
}
})
This is the result of my ajax call from console:
{"campaigns":[{"id":1,"user_id":2,"target_id":1,"name":"Test Campaign","description":"This is a test Campaign","target":"Onboarding","created_at":"-0001-11-30 00:00:00","updated_at":"-0001-11-30 00:00:00","deleted_at":null}]}
I'm not sure why I can't get my vue component to recognize the new data. Anyone see what I'm missing? TIA
Turns out that v-for="campaign in campaigns" should not go on the template tag, but inside of it.
So this:
<template id="campaignBlock" v-for="campaign in campaigns">
<div class="row">
Should be changed to this:
<template id="campaignBlock">
<div class="row" v-for="campaign in campaigns">

change client data transforms value in meteor.js

In my current meteor.js project, user can create a project and add data nodes to it. I'm using D3 to display the nodes in force graph. When they click a particular node from the graph, the corresponding text in the side panel must be highlighted. For this, I need to track with node is selected. But, I don't want to store a "selected" field on the database.
I'm using this data transform to add selected field right now -
/lib/routes.js
Router.route('/project/:code', {
name: 'projectPage',
data: function() {
return {
project: Projects.findOne({code : this.params.code}),
nodes: Nodes.find({project: this.params.code}, {transform: function (doc) {
doc.selected = false;
return doc;
}})
}
}
});
The template is /client/templates/projectPage.html
<template name="projectPage">
<div class="project-page page">
<h3>{{project.title}}</h3>
<p>{{project.summary}}</p>
<div class="work-area">
<div class="map-space">
{{> nodeDisplay nodes=nodes}}
</div>
<div class="type-space">
{{> typeDisplay nodes=nodes}}
</div>
</div>
</div>
</template>
<template name="nodeDisplay">
<div id="svgdiv"></div>
</template>
<template name="typeDisplay">
{{#each nodesData}}
<p>{{text}}</p>
<br/>
{{/each}}
</template>
The click event is handled /client/js/projects.js
Template.nodeDisplay.events({
'click .node':function(event, template){
/*remove previous selection*/
d3.selectAll('.selected circle').attr("r",32);
d3.selectAll('.selected').each(
function(d){
d.fixed = false;
d3.select(this)
.classed('selected', false);
}
);
/*add new selections*/
d3.select(event.currentTarget)
.classed("selected", true)
d3.selectAll('.selected circle').attr("r",40);
var selected_id = $(event.currentTarget).data("id");
Nodes.update(selected_id.toString(), {$set: {selected: true}});
}
});
However, this updates the database to include the "selected" field.
Is there a better way to do this and keep reactivity?
The meteor way is to use session variables and helper functions.
So instead of
Nodes.update(selected_id.toString(), {$set: {selected: true}});
use
Session.set("selected_node", this._id);
and an accompnying helper in Template.typeDisplay.helpers
isNodeSelected: function() {
if(Session.get("selected_node") === this._id) {
return "selected"
}
}
in the template displaying each node (this code assumes that you want to select the corresponding text in the typeDisplay by applying the classname 'selected'):
<template name="typeDisplay">
{{#each nodesData}}
<p class="{{isNodeSelected}}">{{text}}</p>
<br/>
{{/each}}
</template>

Resources