Framework7 Loop Dynamic Content within Route - vue.js

I am using Framework 7 to load demo cards in the router. The problem is I am not sure how to loop through multiple records in the template display.
Here is my route
{
path: '/about/',
async: function (routeTo, routeFrom, resolve, reject) {
// Requested route
// Get external data and return template7 template
app.request.json('data.json', function (data) {
console.log(data);
resolve(
// How and what to load: template
{
template: `<div class="page">
<div class="navbar">
<div class="navbar-inner sliding">
<div class="left">
<a href="#" class="link back">
<i class="icon icon-back"></i>
<span class="ios-only">Back</span>
</a>
</div>
<div class="title">News</div>
</div>
</div>
<div class="page-content">
<div class="card demo-card-header-pic">
<div style="background-image:url({{TitleImg}})" class="card-header align-items-flex-end"></div>
<div class="card-content card-content-padding">
<p class="date">{{Title}}</p>
<p>{{Header}}</p>
</div>
<div class="card-footer">Read more</div>
</div>
</div>
</div>`
},
// Custom template context
{
context: {
ID: data.content.ID,
Title: data.content.Title,
Header: data.content.Header,
Description: data.content.Description,
TitleImg: data.content.TitleImg,
},
}
);
});
}
},
here is sample json:
{
"contentType": "news",
"content": [{
"ID": 1,
"Title": "Test",
"Header": "Short Text",
"Description": "lorem ipsum",
"TitleImg": "/img/collab.jpg"
}, {
"ID": 2,
"Title": "Test2",
"Header": "Short Text2",
"Description": "lorem ipsum2",
"TitleImg": "/img/collab.jpg"
}]
}
Right now it doesn't show anything but I would like to see both entries.
TAKE 2 but still not working.... the items array has my data but the for loop doesnt work
{
path: '/about/',
async: function (routeTo, routeFrom, resolve, reject) {
// Requested route
// Get external data and return template7 template
app.request.json('data.json', function (data) {
for (var i = 0; i < data.content.length; i++) {
items.push({
ID: data.content[i].ID,
TitleImg: data.content[i].TitleImg,
Title: data.content[i].Title,
Header: data.content[i].Header
});
}
console.log(items);
resolve(
{
template: `<div class="page">
<div class="navbar">
<div class="navbar-inner sliding">
<div class="left">
<a href="#" class="link back">
<i class="icon icon-back"></i>
<span class="ios-only">Back</span>
</a>
</div>
<div class="title">News</div>
</div>
</div>
<div class="page-content">
<div class="card demo-card-header-pic" v-for="item in items">
<div style="background-image:url({{TitleImg}})" class="card-header align-items-flex-end"></div>
<div class="card-content card-content-padding">
<p class="date">{{Title}}</p>
<p>{{Header}}</p>
</div>
<div class="card-footer">Read more</div>
</div>
</div>
</div>`
},
{
items: items,
}
);
});
}
},
EDIT - Working solution thanks #djiggy
{{#each items}}
<div class="card demo-card-header-pic">
<a href="/about/{{ID}}/">
<div style="background-image:url({{TitleImg}})" class="card-header align-items-flex-end"><div class="card-headerTxt">{{Title}}</div></div>
<div class="card-content card-content-padding">
<p>{{Header}}</p>
</div>
</a>
</div>
{{/each}}

When you use data as Template7, you have to use Template7 syntax (cf. expressions syntax section)
So in your case, you have to update v-for to each block
Useful link : Access to object with each

Related

Cannot display data from an API using v-for in vuejs

I cannot get or display data from an API but the API is working fine and when I click the button, the data appears,
I want it to appear automatically
I'm using Axios method to connect to my API
I'm new to Vue.js and this is my simple code
var Ve = new Vue({
el: "#app",
data: {
products: [],
},
methods: {
getData: function(){
axios.get('http://localhost:8000/api/products')
.then(data => this.products = data.data)
.catch(err => console.log(err));
}
},
})
THIS IS WHERE I WANT TO DISPLAY MY DATA
<div class="col-sm-9 padding-right" id="app" >
<div class="features_items"><!--features_items-->
<h2 class="title text-center">المنتجات</h2>
<div class="col-sm-4" v-for="item in products">
<div class="product-image-wrapper">
<div class="single-products">
<div class="productinfo text-center">
<img src="images/products/2.jpeg" alt="" />
<h2>${{ item.price }}</h2>
<p>{{ item.name }}</p>
<i class="fa fa-shopping-cart"></i>أضف إلى السلة
</div>
<div class="product-overlay">
<div class="overlay-content">
<h2>${{ item.price }}</h2>
<p>{{ item.name }}</p>
<i class="fa fa-shopping-cart"></i>أضف إلى السلة
</div>
</div>
</div>
<div class="choose">
<ul class="nav nav-pills nav-justified">
<li><i class="fa fa-plus-square"></i>أضف إلى المفضلة</li>
</ul>
</div>
</div>
</div>
</div><!--features_items-->
<button type="button" #click="getData()">show</button>
</div>
I want it to appear automatically I'm using Axios method to connect to my API
As per my understanding, You want to bind the API data on component load. If Yes, You can call getData() method in the mounted() life cycle hook.
mounted hook used to run code after the component has finished the initial rendering and created the DOM nodes.
Demo :
var vm = new Vue({
el:"#app",
data: {
products: [],
},
mounted() {
this.getData();
},
methods: {
getData() {
// Here make an API call and bind the response in products.
this.products = [{
name: 'product1',
price: 50
}, {
name: 'product2',
price: 100
}, {
name: 'product3',
price: 150
}, {
name: 'product4',
price: 200
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="(item, index) in products" :key="index">{{ item.name }} - {{ item.price }}</li>
</ul>
</div>

Cloning div with vue

<template>
<b-form #submit.prevent="Submit" class="mb-5">
<div class="inputArea" v-for="input in inputs" :key="input.id">
<b-form-group label-cols-sm="2" label="Solution (EN)">
<ckeditor :editor="ckeditor" v-model="form.body.en" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.en']">
<div v-for="err in errors['body.en']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (FR)">
<ckeditor :editor="ckeditor" v-model="form.body.np" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.np']">
<div v-for="err in errors['body.np']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
<b-form-group label-cols-sm="2" label="Body (IT)">
<ckeditor :editor="ckeditor" v-model="form.body.in" :config="ckeditorConfig"></ckeditor>
<div v-if="errors['body.in']">
<div v-for="err in errors['body.in']" :key="err">
<small class="text-danger">{{ err }}</small>
</div>
</div>
</b-form-group>
</div>
<b-form-group label="" label-cols-sm="2">
<b-button type="button" class="text-white" variant="dark" #click="addRow">Add row</b-button>
</b-form-group>
<b-form-group label="" label-cols-sm="2">
<b-button type="submit" class="text-white" variant="dark">Submit</b-button>
</b-form-group>
</b-form>
</template>
<style lang="scss">
</style>
<script>
import CKEditor from '#ckeditor/ckeditor5-vue2'
import ClassicEditor from '#ckeditor/ckeditor5-build-classic'
export default {
name: 'Interaction',
components: {
ckeditor: CKEditor.component
},
data(){
return{
counter: 0,
inputs: [
{
en: '',
np: '',
in: '',
}],
form: {
body: [
{
en: '',
np: '',
in: '',
}
],
},
errors: {},
ckeditorData: '<p></p>',
ckeditorConfig: {
// The configuration of the editor
},
ckeditor: ClassicEditor
}
},
methods: {
Submit(){
this.storing = true
this.errors = {}
var self = this
axios.post('/this-is-a-post-url', this.form)
.then(function(response){
console.log(response)
})
},
addRow() {
this.inputs.push({
en: '',
it: '',
fr: '',
id: `${++this.counter}`,
value: '',
});
}
}
}
</script>
I will have array coming in the body name so I am trying to to clone the clone body on a click of a button which has a function AddRow. I want to clone the three fields en,np,in and I want it work like normal html works in this. Example when we clone html form it create input field like so <input name="body['en'][0]"> and when we clone another time it creates something like this <input name="body['en'][1]">.
I have the above code, it clones the body but it also clones the added text before cloning. I want to add an empty field while cloning and also want to update v-model. How can I do that?
Refer below example:
https://codepen.io/telen/pen/OeNZVV
<main class="container">
<form id="app" data-apartments='[{ "price": "23000", "rooms": "12" }, { "price": "42000", "rooms": "32" }]'>
<h1>
Dynamic apartment forms
</h1>
<hr>
<div class="row">
<div class="col-xs-2">
<button type="button" v-on:click="addNewApartment" class="btn btn-block btn-success">
Add +
</button>
</div>
<div class="col-xs-10">
Would you like add more apartments?
</div>
</div>
<div v-for="(apartment, index) in apartments">
<div class="row">
<div class="col-xs-2">
<label> </label>
<button type="button" v-on:click="removeApartment(index)" class="btn btn-block btn-danger">
Rem -
</button>
</div>
<div class="form-group col-xs-5">
<label>Price (HUF)</label>
<input v-model="apartment.price" type="number"
name="apartments[][price]" class="form-control" placeholder="Price">
</div>
<div class="form-group col-xs-5">
<label>Rooms (PCS)</label>
<input v-model="apartment.rooms" type="number"
name="apartments[][rooms]" class="form-control" placeholder="Rooms">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<button type="submit" v-on:click.prevent="sumbitForm" class="btn btn-block btn-primary">
Submit
</button>
</div>
<div class="col-xs-10">
Open the console (F12) and see the result
</div>
</div>
<hr>
<pre>{{ $data }}</pre>
</form>
JS:
window.app = new Vue({
el: '#app',
data: {
apartment: {
price: '',
rooms: ''
},
apartments: [],
},
mounted: function () {
/*
* The "data-apartments" could come from serverside (already saved apartments)
*/
this.apartments = JSON.parse(this.$el.dataset.apartments)
},
methods: {
addNewApartment: function () {
this.apartments.push(Vue.util.extend({}, this.apartment))
},
removeApartment: function (index) {
Vue.delete(this.apartments, index);
},
sumbitForm: function () {
/*
* You can remove or replace the "submitForm" method.
* Remove: if you handle form sumission on server side.
* Replace: for example you need an AJAX submission.
*/
console.info('<< Form Submitted >>')
console.info('Vue.js apartments object:', this.apartments)
window.testSumbit()
}
}
})
/*
* This is not Vue.js code, just a bit of jQuery to test what data would be submitted.
*/
window.testSumbit = function () {
if (!window.jQuery) {
console.warn('jQuery not present!')
return false
}
console.info('Submitted (serverside) array:', jQuery('form').serializeJSON())
}

How do I make the hoverable dropdown close when navigating to a differerent link in Bulma?

HERE is a SANDBOX with the issue on it
I have a hoverable dropdown inside a Navbar
When I move to a different page, the dropdown is still open
I have tried this in plain Bulma, the issue still remains
I am on Nuxt.js using SSR
I am using nuxt-link / equivalent of Vue router-link to navigate to a different page.
Here is the my default.vue file
<template>
<div class="ch-container">
<header class="ch-header">
<nav
class="navbar is-fixed-top"
role="navigation"
aria-label="main navigation"
>
<div class="navbar-brand">
<nuxt-link class="navbar-item" to="/">
<img
alt="CH Logo"
src="https://i.imgur.com/v35Kfc9.png"
width="28"
height="28"
/>
</nuxt-link>
<a
role="button"
class="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
data-target="navbarBasicExample"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<nuxt-link class="navbar-item" to="/news">
News
</nuxt-link>
<nuxt-link class="navbar-item" to="/resources">
Resources
</nuxt-link>
<nuxt-link class="navbar-item" to="/tickers">
Tickers
</nuxt-link>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
More
</a>
<div class="navbar-dropdown">
<a class="navbar-item">
FAQ
</a>
<nuxt-link class="navbar-item" to="/contact">
Contact
</nuxt-link>
<hr class="navbar-divider" />
<a class="navbar-item">
Feature Request
</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<a href="#">
<fa :icon="faMoon" />
</a>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link is-arrowless">
<fa :icon="faExclamationCircle" />
</a>
<div class="navbar-dropdown">
<a class="navbar-item">
No new notifications
</a>
</div>
</div>
<div class="navbar-item">
<div class="buttons">
<nuxt-link class="button is-primary" to="/signup">
<strong>Sign up</strong>
</nuxt-link>
<nuxt-link id="login" class="button is-light" to="/login">
Log in
</nuxt-link>
</div>
</div>
</div>
</div>
</nav>
</header>
<main class="ch-main">
<nuxt />
</main>
<footer class="ch-footer is-hidden-mobile">
<div class="level">
<div class="level-left">
<div class="level-item">
<a href="#">
<span class="icon">
<fa :icon="faFacebookSquare" />
</span>
</a>
<a href="#">
<span class="icon">
<fa :icon="faTwitterSquare" />
</span>
</a>
<a href="#">
<span class="icon">
<fa :icon="faRedditSquare" />
</span>
</a>
</div>
</div>
<div class="level-right">
<div class="level-item">
©ch, All Rights Reserved
</div>
<div class="level-item">
<nuxt-link to="/contact">Contact</nuxt-link>
</div>
<div class="level-item">
<nuxt-link to="/terms-of-service">Terms</nuxt-link>
</div>
<div class="level-item">
<nuxt-link to="/privacy-policy">Privacy</nuxt-link>
</div>
</div>
</div>
</footer>
</div>
</template>
<script>
import {
faFacebookSquare,
faTwitterSquare,
faRedditSquare,
} from '#fortawesome/free-brands-svg-icons'
import { faMoon, faExclamationCircle } from '#fortawesome/free-solid-svg-icons'
export default {
computed: {
faFacebookSquare() {
return faFacebookSquare
},
faTwitterSquare() {
return faTwitterSquare
},
faRedditSquare() {
return faRedditSquare
},
faMoon() {
return faMoon
},
faExclamationCircle() {
return faExclamationCircle
},
},
mounted() {
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(
document.querySelectorAll('.navbar-burger'),
0
)
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach((el) => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target
const $target = document.getElementById(target)
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active')
$target.classList.toggle('is-active')
})
})
}
},
}
</script>
<style></style>
Here is a GIF illustrating the problem
How to close the dropdown after you move to a different page?
Ok, the whole thing makes it complicated, because the hover is triggered by css and therefore the dropdown can always be seen when the mouse is over it. You have to overwrite this state and solve it with vue events. We also have to put a watcher on the route to reset the state.
CodeSandbox - Example
<template>
<div class="container">
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<!-- <a class="navbar-item" href="https://bulma.io"> -->
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28">
<a
role="button"
class="navbar-burger burger"
aria-label="menu"
aria-expanded="false"
data-target="navbarBasicExample"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item">Home</a>
<a class="navbar-item">Documentation</a>
<div
#mouseover="toggleDropdown(true)"
#mouseleave="toggleDropdown(false)"
class="navbar-item has-dropdown is-hoverable"
>
<a class="navbar-link">More</a>
<div class="navbar-dropdown" :style="{display: showDropdown ? 'block' : 'none' }">
<nuxt-link class="navbar-item" to="/about">About</nuxt-link>
<nuxt-link class="navbar-item" to="/jobs">Jobs</nuxt-link>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">
<strong>Sign up</strong>
</a>
<a class="button is-light">Log in</a>
</div>
</div>
</div>
</div>
</nav>
<Nuxt/>
</div>
</template>
<script>
export default {
data() {
return {
routeChange: false,
showDropdown: false
};
},
watch: {
$route() {
this.routeChange = true;
this.showDropdown = false;
}
},
methods: {
toggleDropdown(payload) {
if (this.showDropdown !== payload) this.routeChange = false;
if (!this.routeChange) {
this.showDropdown = payload;
}
}
}
};
</script>
This worked form me Bootstrap 5, in touch devices it uses click, on devices with mouse it uses hover
<template>
<span
v-if="item"
class="primary-navigation-list-dropdown"
#mouseover="isTouchscreenDevice ? null : openDropdownMenu()"
#mouseleave="isTouchscreenDevice ? null : closeDropdownMenu()"
>
<nuxt-link
to="#"
#click.prevent.native="openDropdownMenu"
v-click-outside="closeDropdownMenu"
:title="item.title"
:class="[
item.cssClasses,
{ show: isDropdownMenuVisible }
]"
:id="`navbarDropdownMenuLink-${item.id}`"
:aria-expanded="[isDropdownMenuVisible ? true : false]"
class="
primary-navigation-list-dropdown__toggle
nav-link
dropdown-toggle"
aria-current="page"
role="button"
data-toggle="dropdown"
>
{{ item.label }}
</nuxt-link>
<ul
:class="{ show: isDropdownMenuVisible }"
:aria-labelledby="`navbarDropdownMenuLink-${item.id}`"
class="
primary-navigation-list-dropdown__menu
dropdown-menu-list
dropdown-menu"
>
<li
v-for="item in item.children" :key="item.id"
class="dropdown-menu-list__item"
>
<NavLink
:attributes="item"
class="dropdown-menu-list__link dropdown-item"
/>
</li>
</ul>
</span>
</template>
<script>
import NavLink from '#/components/Navigation/NavLink';
export default {
name: "DropdownMenu",
props: {
item: {
type: Object,
required: true,
},
},
data() {
return {
isDropdownMenuVisible: false,
isTouchscreenDevice: false
};
},
mounted() {
this.detectTouchscreenDevice();
},
methods: {
openDropdownMenu() {
if (this.isTouchscreenDevice) {
this.isDropdownMenuVisible = !this.isDropdownMenuVisible;
} else {
this.isDropdownMenuVisible = true;
}
},
closeDropdownMenu() {
if (this.isTouchscreenDevice) {
this.isDropdownMenuVisible = false;
} else {
this.isDropdownMenuVisible = false;
}
},
detectTouchscreenDevice() {
if (window.PointerEvent && ('maxTouchPoints' in navigator)) {
if (navigator.maxTouchPoints > 0) {
this.isTouchscreenDevice = true;
}
} else {
if (window.matchMedia && window.matchMedia("(any-pointer:coarse)").matches) {
this.isTouchscreenDevice = true;
} else if (window.TouchEvent || ('ontouchstart' in window)) {
this.isTouchscreenDevice = true;
}
}
return this.isTouchscreenDevice;
}
},
components: {
NavLink
}
};
</script>
<style scoped lang="scss">
.primary-navigation-list-dropdown {
&__toggle {
color: $white;
&:hover {
color: $blue;
}
}
&__menu {
margin-top: 0;
}
&__dropdown {
}
}
.dropdown-menu-list {
&__item {
}
&__link {
&.active,
&.nuxt-link-exact-active {
border-bottom: 1px solid $blue;
}
}
}
</style>
NavLink.vue
<template>
<component
:is="attributes"
v-bind="linkAttributes(attributes.path)"
:title="attributes.title"
:class="[ attributes.cssClasses ]"
class="nav-link active_"
aria-current="page"
prefetch
>
{{ attributes.label }}
</component>
</template>
<script>
export default {
name: 'NavLink',
props: {
attributes: {
type: Object,
required: true
}
},
methods: {
linkAttributes(path) {
if (path.match(/^(http(s)?|ftp):\/\//) || path.target === '_blank') {
return {
is: 'a',
href: path,
target: '_blank',
rel: 'noopener'
}
}
return {
is: 'nuxt-link',
to: path
}
}
}
}
</script>
click-outside.js
import Vue from 'vue'
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
el.clickOutsideEvent = function (event) {
if (!(el == event.target || el.contains(event.target))) {
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent)
},
unbind: function (el) {
document.body.removeEventListener('click', el.clickOutsideEvent)
},
});
I’m not using Vue, but using Meteor (where similar route-calling trips up the Bulma drop-down removal).
Slightly hacky way to fix it, but the dropdown is made visible because the .has-dropdown element has the .is-hoverable class. So to fix, on any click on the dropdown’s items, I run this:
// Remove the hover effect = dropdown disappears
$(".has-dropdown").removeClass("is-hoverable");
// Tiny time later, put it back, so hover-drop works anew
setTimeout(function() {
$(".has-dropdown").addClass("is-hoverable");
}, 100);
Doesn’t really matter that it would hit all the dropdowns if you have more than one, because resetting them all is harmless when routing to a new page. But if you’re fussy you could target just the closest dropdown.
As Bulma’s mobile view doesn’t activate an on-hover effect anyway, this doesn’t break in the mobile “burger menu” version of my navbar.
Works OK for my project on Chrome, Safari, Firefox.

Local-Storage in Vue.JS

I am working on Vue.JS and I tried to use local-storage with it to save data. In my code, I can store and retrieve all data with local-storage except line-through effect. Here, I am trying to store actual boolean value of line-through effect in local-storage and want to retrieve that value on to-do list app.
<title>To Do List</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>
<style>
.taskDone {
text-decoration: line-through;
}
</style>
</head>
<body>
<div id="todo-list" class="container">
<div class="container col-sm-8 col-sm-offset-2">
<h1 class="text-center"> <big><b> To Do List </b> </big></h1>
<h5 class="text-center"> <span v-show="itemsTodo.length"> ({{ itemsTodo.length }} pending) </span></h5>
<div class="col-md-8">
<button v-if="state === 'default'" class="btn btn-primary" #click="changeState('edit') ">Add Item</button>
<button v-else class="btn btn-info" #click="changeState('default')">Cancel</button>
</div>
<br>
<br>
<div v-if="state === 'edit'" >
<div class="col-sm-4">
<input class='form-control' v-model="newItem" type="text" placeholder="Type here" #keyup.enter="saveItem" >
</div>
<div class="col-sm-4">
<input class="form-control" v-model="newdate" type="date" type="text"/>
</div>
<div class="col-sm-4">
<button class='btn btn-primary btn-block' v-bind:disabled="newItem.length === 0"#click= "saveItem">Save Item</button>
</div>
</div>
<br>
<br>
<ul type="none" class="list-group">
<li class="list-group-item" v-for="(item,index,date) in items" :class="{taskDone : item.completed}" >
<h4>
<input type="checkbox" v-model="item.completed" #click="item.completed = !item.completed">
<button class="btn btn-primary " #click.stop="removeitems(index)">× </button>
<b><i> {{ item.label }} {{ item.date }} </i></b></h4>
</li>
</ul>
<h2 v-if="items.length === 0">Nice Job! Nothing in TO DO LIST</h2>
<div class="col-sm-4">
<button class="btn btn-warning btn-block" #click="clearcompleted"> Clear Completed</button>
</div>
<div class="col-sm-4">
<button class="btn btn-danger btn-block" #click="clearAll"> Clear All</button>
</div>
</div>
</div>
2. Vue.JS code
<script src="https://unpkg.com/vue" ></script>
<script>
var todolist = new Vue({
el: '#todo-list',
data : {
state : 'edit',
header: 'To Do List',
newItem: '',
newdate: '',
items: [
{
label:'coffee',
completed:false,
date:'2019-06-20' ,
},
{
label:'tea',
completed:false,
date:'2019-06-19' ,
},
{
label:'milk',
completed:false,
date:'2019-06-19' ,
},
]
},
computed:{
itemsDone(){
return this.items.filter(items => items.completed)
},
itemsTodo(){
return this.items.filter(items =>! items.completed)
},
},
methods:{
saveItem: function(){
if (this.newItem != ''){
this.items.push({
label:this.newItem,
completed: false,
date : this.newdate,
});
this.newItem = '';
this.newdate = '';
}},
changeState: function(newState){
this.state = newState;
this.newItem = '';
this.newdate = '';
},
removeitems(index){
this.items.splice(index,1);
},
clearcompleted (){
this.items = this.itemsTodo;
},
clearAll: function(){
this.items = [ ];
},
},
mounted(){
console.log('App Mounted!');
if (localStorage.getItem('items')) this.items = JSON.parse(localStorage.getItem('items'));
},
watch: {
items:{
handler(){
localStorage.setItem('items',JSON.stringify(this.items));
},
},
},
});
</script>
I expect correct boolean value of line-through effect to be stored in local-storage. So that, appropriate effect will show on browser.
You are just watching items. If you change something in a item (in your case completed) the handler will not be called and your change is not stored.
You could use a "deep" watcher but i suggest to call your save logic whenever you changed something.

Is it possible to use Vue-sweetalert2 html as vue component?

I use this package https://www.npmjs.com/package/vue-sweetalert2 and I want to past vue component in Vue.swal as html.
<template>
<div class="w-full">
<div class="py-6 w-full">
<button
type="button"
class="btn btn-default btn-primary"
#click="openTeamsModal"
>
Teams
</button>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import TeamTable from "./TeamTable";
import VueSweetalert2 from 'vue-sweetalert2';
Vue.use(VueSweetalert2);
export default {
components: {TeamTable},
props: [
'resourceName',
'resourceId',
'field'
],
data: () => ({
teams: [],
}),
methods: {
openTeamsModal() {
Nova.request().get(`/api/competitors/${this.field.seasonId}/${this.field.championshipId}`).then( responce => {
console.log(responce)
});
Vue.swal({
title: 'Test',
html: '<team-table></team-table>',
});
}
},
}
</script>
but there is nothing. I am new to VueJs and I still don’t fully understand how to insert my components as html.
Yes! is possible! ... after hours of research, I have succeeded.
this is the way:
you need to include all the logic of the template between this characters ` `
you will also need edit the vue.config.js file and add inside the configurewebpack object add this: 'vue$':'vue/dist/vue.esm.js'
configureWebpack: {
resolve: {
alias: {
'src': resolveSrc('src'),
'chart.js': 'chart.js/dist/Chart.js',
// add this line for include components inside swal alert
'vue$':'vue/dist/vue.esm.js'
}
Once this is done you must relaunch the project "npm run dev"
This is my complete example, tested and working
openSweet() {
Vue.component('my-comp', {
template: `
<div class="card-content">
<div class="span2">
<div class="col-sm-6 col-md-2 col-lg-3">
<div class="row">
<div style="margin-top: 6px;" >
<p-switch v-model="switchTrip.state" type="primary" on-text="ON" off-text="OFF" style="justify-content:center"></p-switch>
<h5 class="card-title" style="margin-left: 25px;">Recorridos</h5>
</div>
</div>
<div class="row">
<div style="margin-top: 6px;" >
<p-switch v-model="switchVel.state" type="primary" on-text="ON" off-text="OFF" style="justify-content:center"></p-switch>
<h5 class="card-title" style="margin-left: 25px;">Velocidad</h5>
</div>
</div>
</div>
</div>
<div class="span2">
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="row">
<div >
<input type="search" class="form-control input-sm" placeholder="km / h" v-model="vmax">
<h5 class="card-title">Vel. Max</h5>
</div>
</div>
<div class="row">
<div>
<input type="search" class="form-control input-sm" placeholder="minutos" v-model="tol">
<h5 class="card-title">Tolerancia</h5>
</div>
</div>
</div>
</div>
</div>
`,
data () {
return {
switchVel: {
state: false
},
switchEvent: {
state: false
},
switchTrip: {
state: false
},
search: '',
vmax: '',
tol: ''
}
},
components: {
[Button.name]: Button,
Card,
PSwitch
}
})
new Vue({
el: '#modal',
beforeCreate: () => {
swal({
titleText: "Descarga de Reportes",
showCancelButton: true,
cancelButtonText: 'Cancelar',
confirmButtonText: 'Descargar',
// confirmButtonAriaLabel: 'glyphicon glyphicon-ok-sign',
// cancelButtonAriaLabel: 'glyphicon glyphicon-remove-sign',
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
width: 800,
html: '<div id="modal"><my-comp></my-comp></div>'
})
}
})
}
I hope it helps you
Greetings from Argentina
https://github.com/aledc7