VueJS Nested Builder Example - javascript

I'm new to VueJS and am trying to make a small page builder application where you can create sections and add subsections to each of those. I'm not sure how to setup the Vue data property to allow this. Any insight on how you would go about doing something like this would be appreciated. Here's my code so far:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div id="app">
<form>
<input type="text" v-model="title"> {{title}}<br>
<button type="button" v-on:click="addSection()">Add Section</button>
</form>
<h1>Sections</h1>
<div v-for="(section, index) in sections">
<h2>{{section.title}}</h2>
<form>
<input type="text" v-model="subTitle"> {{subTitle}}<br>
<button type="button" v-on:click="addSubSection()">Add SubSection</button>
</form>
<div v-for="(subsection, index) in subsections">
<h3>{{subsection.subTitle</h3>
</div>
</div>
</div>
<script src="js/vue.min.js"></script>
<script>
var app = new Vue({
el: '#app',
data: {
title: '',
sections: []
},
methods: {
addSection: function(e) {
this.sections.push({title: this.title});
this.title = '';
},
addSubSection: function(sectionIndex) {
this.sections[sectionIndex].push({subTitle: this.subTitle});
this.subTitle = '';
}
}
});
</script>
</body>

Each of your sections is an object, not an array so this.sections[sectionIndex].push() won't work. You should probably add a sections property to each new section, eg
this.sections.push({ title: this.title, sections: [] })
and when adding a sub-section
this.sections[sectionIndex].sections.push({ subTitle: this.subTitle })
You should also have a data property for subTitle

Related

VueJs filters have no effect

Simple code example
<!DOCTYPE html>
<html>
<head>
<title>My first Vue app</title>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.10/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<style>
</style>
</head>
<body>
<div id="app">
<h1>Bitcoin Price Index</h1>
<div v-for="currency in info">
{{ currency.description }}
<span v-html="currency.symbol"></span>{{ currency.rate_float || currencyToDeciaml }}
</div>
</div>
<script>
const app = new Vue({
el : '#app',
data : {
info : null,
},
filters : {
currencyToDeciaml(val) {console.log(`foo`);
return Number(val).toFixed(2);
}
},
// Dom is ready so now load the data
mounted() {
axios.get(`https://api.coindesk.com/v1/bpi/currentprice.json`)
.then(response => this.info = response.data.bpi);
},
});
</script>
</body>
</html>
I am trying to apply a simple filter currencyToDeciaml but it doesn't even get executed and foo does not display. I cannot seem to figure it out. Any help would be appreciated.
The correct syntax for filters is this:
{{ currency.rate_float | currencyToDeciaml }}
with only one pipe

Using Vue.js: disabling button on picture slideshow, when no "next" photo is available

This is my first time using Vue. I am trying to create a slideshow from an array of images. I have am able to disable my "previous" button, when the user is at the beginning of the slideshow, but cannot disable my "next" button when at the last image of the slide show.
Here is my code:
Vue.config.devtools = true
var app = new Vue({
el: '#app',
data: {
title: 'Photo of the day!',
description: '',
images: [
{
image: 'https://cdn.spacetelescope.org/archives/images/wallpaper2/heic1509a.jpg', date: '1/9/2019', title: 'Beautiful Milky Way'
},
{
image: 'https://img.purch.com/w/660/aHR0cDovL3d3dy5zcGFjZS5jb20vaW1hZ2VzL2kvMDAwLzA2MS8wNzUvb3JpZ2luYWwvY2hhbmRyYS1uZ2M2MzU3LWNvbXBvc2l0ZS5qcGc=', date: '1/10/2019', title: 'Amazing Whirlpool Galaxy'
},
{
image: 'https://icdn3.digitaltrends.com/image/space-engine-featured-510x0.jpg?ver=1', date: '1/11/2019', title: 'Wonderous Large Magellanic Cloud'
},
],
currentNumber: 0,
photosAvailable: true,
},
methods: {
next: function() {
app.currentNumber += 1;
if (app.currentNumber === app.images.length) {
console.log('SERGIO')
app.photosAvailable = false
return
}
},
previous: function() {
app.photosAvailable = true
return app.currentNumber -= 1
},
}
})
<!DOCTYPE html>
<html>
<head>
<link href="./styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Anaheim" rel="stylesheet">
<meta charset="UTF-8">
<title>NASA Photo Of The Day</title>
</head>
<body>
<div id='app'>
<section class='hero'>
<h1 class='title'>{{ title }}</h1>
</section>
<section class='picture-area'>
<div class='info'>
<h2>{{ images[currentNumber].title }}</h2>
<p v-bind='description'>{{ description }}</p>
<img class='image-of-day' :src='images[currentNumber].image' />
<p class='date'>{{ images[currentNumber].date }}</p>
<button :disabled="!currentNumber" v-on:click="previous" class='backward'>previous</button>
<button :disabled="!photosAvailable" v-on:click="next" :class="{disabledButton: !photosAvailable}" class='forward'>next</button>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/axios#0.12.0/dist/axios.min.js"></script>
<script src='./index.js'></script>
</body>
</html>
In my Vue devtools, I can see that photosAvailable does turn to false, which should change the button to disabled, but it is not.
Hope someone can catch my error, as it is my first time using Vue.
Here's one approach that you can use to make it work including the parts that you should improve on your current code.
Replace app with this under your methods since using app will cause an error since it's undefined. Use this if you want to get access to any state or method under your component.
Since the status of the next and prev buttons are derived from the value of currentNumber of slide, you can define isPrevPhotoAvailable and isNextPhotoAvailable methods under the computed property of your component. With this, you can remove isPhotosAvailable from your state.
Vue.config.devtools = true
var app = new Vue({
el: '#app',
data: {
title: 'Photo of the day!',
description: '',
images: [
{
image: 'https://cdn.spacetelescope.org/archives/images/wallpaper2/heic1509a.jpg', date: '1/9/2019', title: 'Beautiful Milky Way'
},
{
image: 'https://img.purch.com/w/660/aHR0cDovL3d3dy5zcGFjZS5jb20vaW1hZ2VzL2kvMDAwLzA2MS8wNzUvb3JpZ2luYWwvY2hhbmRyYS1uZ2M2MzU3LWNvbXBvc2l0ZS5qcGc=', date: '1/10/2019', title: 'Amazing Whirlpool Galaxy'
},
{
image: 'https://icdn3.digitaltrends.com/image/space-engine-featured-510x0.jpg?ver=1', date: '1/11/2019', title: 'Wonderous Large Magellanic Cloud'
},
],
currentNumber: 0
},
computed: {
isNextPhotoAvailable: function() {
return this.currentNumber + 1 !== this.images.length;
},
isPrevPhotoAvailable: function() {
return this.currentNumber - 1 !== -1;
}
},
methods: {
next: function() {
this.currentNumber += 1;
},
previous: function() {
return this.currentNumber -= 1;
},
}
})
<!DOCTYPE html>
<html>
<head>
<link href="./styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Anaheim" rel="stylesheet">
<meta charset="UTF-8">
<title>NASA Photo Of The Day</title>
</head>
<body>
<div id='app'>
<section class='hero'>
<h1 class='title'>{{ title }}</h1>
</section>
<section class='picture-area'>
<div class='info'>
<h2>{{ images[currentNumber].title }}</h2>
<p v-bind='description'>{{ description }}</p>
<img class='image-of-day' :src='images[currentNumber].image' />
<p class='date'>{{ images[currentNumber].date }}</p>
<button :disabled="!isPrevPhotoAvailable" v-on:click="previous" class='backward'>previous</button>
<button :disabled="!isNextPhotoAvailable" v-on:click="next" :class="{disabledButton: !isNextPhotoAvailable}" class='forward'>next</button>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/axios#0.12.0/dist/axios.min.js"></script>
<script src='./index.js'></script>
</body>
</html>
Maybe try putting the logic in computed?

Refer vue.js data but nothing

1.I am a beginner of vue.js, but when I was trying some examples, I found something uncommon. The first one is when I set id in the body, and write my js code as followed:
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="./css/semantic.css">
<script type="text/javascript" src="js/vue.js">
</script>
<title></title>
</head>
<body style="background-color:black;" id="app">
<div class="ui container" style="margin:20px;">
<div class="ui segment">
<h1>{{ title }}</h1>
<p>
{{ message }}
</p>
</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
message: "Hello, world!",
title: "How about you?"
}
})
</script>
</body>
</html>
And this is my result which does not show me data :
2.And the second problem is when I created an object in the data, and I refer it as followed, it also does not work in the div label.
This is the code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="./css/semantic.css">
<script type="text/javascript" src="js/vue.js">
</script>
<title></title>
</head>
<body style="background-color:black;">
<div class="ui container" style="margin:20px;">
<div class="ui segment" id="app">
<h1>{{ article.title }}</h1>
<p>
{{ article.message }}
</p>
</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
article{
message: "Hello, world!",
title: "How about you?"
}
}
})
</script>
</body>
</html>
So I wonder if there some conflicts when I was using semanticUI and vue.js?
As a best practice, you can create a top level div#app, like this:
var app = new Vue({
el: "#app",
data: {
message: "Hello, world!",
title: "How about you?"
}
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<body style="background-color:black;">
<div id="app"><!-- just a wrapper for vuejs -->
<div class="ui container" style="margin:20px;">
<div class="ui segment">
<h1>{{ title }}</h1>
<p>
{{ message }}
</p>
</div>
</div>
</div>
</body>

How do I swap content

how can I swap content of a div with Vue.js? I think I lack general lifecycle knowledge. Here is what I´ve got so far. After all I need to swap between two Vue-instances and ´d like to use only one lightbox container for them.
Here is what I´ve got so far: http://jsbin.com/qokerah/edit?html,js,output
HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script type="x-template" id="foo-template">
<div class="text">{{ fooText }}</div>
<div class="confirm" v-if="fooConfirm">confirmed</div>
</script>
<script type="x-template" id="bar-template">
<div class="heading">{{ barHeading }}</div>
<div class="info">{{ barInfo }}</div>
</script>
<div class="foo">
<div class="btn btn-primary" v-on:click="swapLightboxContent">Open foo template</div>
</div>
<div class="bar">
<div class="btn btn-primary" v-on:click="swapLightboxContent">Open bar template</div>
</div>
<div class="lightbox">
<div class="lightbox-content">Show foo- or bar-template</div>
</div>
</body>
</html>
JS
var foo = new Vue({
el: '.foo',
data: {
fooText: 'text',
fooConfirm: false
},
methods: {
swapLightboxContent: function () {
console.log('Show foo-template');
}
}
});
var bar = new Vue({
el: '.bar',
data: {
barHeading: 'text',
barInfo: 'text'
},
methods: {
swapLightboxContent: function () {
console.log('Show bar-template');
}
}
});
Ok, my main misconception where:
I Used var foo and bar as new Vue() instances without having a parent "intersection" instance
so this is now working:
http://jsbin.com/tiwoco/edit?html,js,output
Still need to figure out if accessing the currentView item through vmFoo and vmBar instances shouldn´t be done in foo and bar components :)

Simple Backbone app not working

I wrote simple Backbone.js app from manual, but this does't work. Why?
It is a HTML-code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="main.css">
<script src="source/jquery.js"></script>
<script src="source/underscore.js"></script>
<script src="source/backbone.js"></script>
<script src="main.js"></script>
</head>
<body>
<div id="menu">
<ul>
<li>Start</li>
<li>Success</li>
<li>Error</li>
</ul>
</div>
<div id="start" class="block">
<div class="userplace">
<label>Enter name<input type="text" id="username"></label>
</div>
<div class="buttonplace">
<input type="button" id="button" value="Check">
</div>
</div>
<div id="error" class="block">
<p>Error - not found!</p>
</div>
<div id="success" class="block">
<p>Win!</p>
</div>
</body>
</html>
And it is a JS-code:
var Controller = Backbone.Router.extend({
routes: {
'': 'start',
'!/': 'start',
'!/error': 'error',
'!/success': 'success'
},
start: function() {
$('.block').hide();
$('#start').show();
},
error: function() {
$('.block').hide();
$('#error').show();
},
success: function() {
$('.block').hide();
$('#success').show();
},
});
var controller = new Controller();
var Start = Backbone.View.extend({
el: '#start',
events: {
'click #button': 'check'
},
check: function() {
console.log('WiN!');
if($("#username").val() == 'test') {
controller.navigate('success', true);
}
else {
controller.navigate('error', true);
}
}
});
var starter = new Start();
Backbone.history.start();
When I select point in menu, all work normal, but when I entered name into field and press button nothing happens. Event not activated. Why?
I think you're calling navigate incorrectly.
Try this:
controller.navigate('!/success', {trigger:true});
Documentation:
http://backbonejs.org/#Router-navigate

Categories

Resources