I am developing an e-commerce window and it was working perfectly until the part where I needed to add items to the cart. the browser console showed an error when I wanted to display the items in the cart. However, the strange thing is that it works perfectly in the incognito window. What could be the issue?
Below are my two files:
Code for the cart.vue file:
<template>
<div class="page-cart">
<div class="columns is-multiline">
<div class="column is-12">
<h1 class="title">Cart</h1>
</div>
<div class="column is-12 box">
<table class="table is-fullwidth" v-if="cartTotalLength">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th></th>
</tr>
</thead>
<tbody>
<CartItem
v-for="item in cart.items"
v-bind:key="item.product.id"
v-bind:initialItem="item"
v-on:removeFromCart="removeFromCart"/>
</tbody>
</table>
<p v-else>Are you gonna stay hungry?...😕</p>
</div>
<div class="column is-12 box">
<h2 class="subtitle">Summary</h2>
<strong>Ksh{{ cartTotalPrice.toFixed(2) }}</strong>, {{ cartTotalLength }} items
<hr>
<router-link to="/cart/checkout" class="button is-dark">Proceed to checkout</router-link>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import CartItem from '#/components/CartItem.vue'
export default {
name: 'Cart',
components: {
CartItem
},
data() {
return {
cart: {
items: []
}
}
},
mounted() {
this.cart = this.$store.state.cart
},
methods: {
removeFromCart(item) {
this.cart.items = this.cart.items.filter(i => i.product.id !== item.productid)
}
},
computed: {
cartTotalLength() {
return this.cart.items.reduce((acc, curVal) => {
return acc += curVal.quantity
}, 0)
},
cartTotalPrice() {
return this.cart.items.reduce((acc, curVal) => {
return acc += curVal.product.price * curVal.quantity
}, 0)
},
}
}
</script>
The following code is for a component, cartItem.vue:
<template>
<tr>
<td><router-link :to="item.product.get_absolute_url">{{ item.product.name }}</router-link></td>
<td>Ksh{{ item.product.price }}</td>
<td>
{{ item.quantity }}
<a #click="decrementQuantity(item)">-</a>
<a #click="incrementQuantity(item)">+</a>
</td>
<td>Ksh{{ getItemTotal(item).toFixed() }}</td>
<td><button class="delete" #click="removeFromCart(item)"></button></td>
</tr>
</template>
<script>
export default {
name: 'CartItem',
props: {
initialItem: Object
},
data() {
return {
item: this.initialItem
}
},
methods: {
getItemTotal(item) {
return item.quantity * item.product.price
},
decrementQuantity(item) {
item.quantity -= 1
if (item.quantity === 0) {
this.$emit('removeFromCart', item)
}
this.updateCart()
},
incrementQuantity(item) {
item.quantity += 1
this.updateCart()
},
updateCart() {
localStorage.setItem('cart', JSON.stringify(this.$store.state.cart))
},
removeFromCart(item) {
this.$emit('removeFromCart', item)
this.updateCart()
},
},
}
</script>
I also noted that the phone browser could not open some contents of the website on the network. Especially the contents from the server are not opened in my phone's browser. I am using Bulma CSS framework.
As I don't know the error from the console, I could only guess the problem.
You should try to use a different browser, or at least remove the data (cookies, storage) for your site, and see what happens. Perhaps there is some old previous data that would lead to a problem.
Related
I'm trying to get a transition (animation) working on an HTML table. I've got it working for a list but not for a table. It works when using vue 2.
My code is adapted from this fiddle.
This is the HTML
<div id="app">
<div class="row p-2">
<div class="col-6">
<h2>List</h2>
<transition-group class="list-group" name="fruit-list" tag="ul">
<li class="list-group-item" v-for="item in items" :key="item.id">
<div class="d-flex align-items-center">
<div>
{{ item.name }}
</div>
</div>
</li>
</transition-group>
</div>
<div class="col-6">
<h2>Table</h2>
<table class="table mb-0">
<thead>
<tr>
<th scope="col">Fruit</th>
</tr>
</thead>
<tbody name="fruit-table" is="transition-group">
<tr v-for="item in items" :key="item.id">
<th scope="row">{{ item.name }}</th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
This is the CSS
<style>
.fruit-list-move {
transition: transform 1s;
}
.fruit-table-move {
transition: transform 1s;
}
</style>
This is the javascript
<script>
const myapp = {
data() {
return {
items: [
{
id: 1,
name: "Bananas",
quantity: 5
}, {
id: 2,
name: "Apples",
quantity: 3
}, {
id: 4,
name: "Oranges",
quantity: 1
}, {
id: 5,
name: "Stawberries",
quantity: 25
},
]
}
},
mounted() {
this.addItem()
},
methods: {
addItem() {
this.items.splice(2, 0, {
id: 3,
name: "Kiwis",
quantity: 8
})
setTimeout(() => {
this.moveItems()
}, 2000)
},
moveItems() {
this.items = this.items.reverse()
setTimeout(() => {
this.removeItem()
}, 2000)
},
removeItem() {
this.items.splice(2, 1)
setTimeout(() => {
this.addItem()
}, 2000)
}
}
}
app = Vue.createApp(myapp)
app.mount('#app')
</script>
To be honest I am also a little confused about whether Vue 3 is "ready". The homepage still directs to Vue 2 by default.
Hacky hack is here...
<tbody tag="tbody" name="list" is="transition-group">
<tr v-for="..." :key="...">...</tr>
<tbody>
Example (Warning: writed with pug)
Table have trouble with animation because tr must be in tbody or browser reassembly tree...
To fix that you must transform tbody into transition-group and Vue 3 changed some details.
is="..." -> is="vue:..."
transition-group now ephemeral without tag attr.
isGridView: true,
isListView: true,
methods: {
switchView: function() {
this.isGridView = !this.isGridView;
},
switchData: function () {
this.isListView = !this.isListView;
}
<div class="product-grid1">item1</div>
<div class="product-grid2">item2</div>
<div class="product-grid3">item3</div>
<div class="product-list1">item1</div>
<div class="product-list2">item2</div>
<div class="product-list3">item3</div>
<div id="app-gridview">
<div>
<button class="button" v-on:click="switchView()"></button>
<button class="button" v-on:click="switchData()"></button>
</div>
<div v-bind:class="[ isGridView ? 'grid-wrapper' : 'list-wrapper' ]">
<div class="grid-row" v-if="isGridView">
<div class="grid-header" v-for="name in gridData.columns">{{ name }}</div>
</div>
<!-- GridView structure -->
<div v-if="isGridView" class="grid-row" v-for="row in gridData.data">
<div class="list-row-item" v-for="name in gridData.columns">
<div>{{ row[name] }}</div>
</div>
</div>
<!-- ListView structure -->
<div v-if="!isGridView" class="list-row" v-for="row in gridData.data">
<img v-bind:src="row.ImagePath" class="list-image" />
<div class="list-property">
<div class="list-row-item" v-for="name in gridData.columns">
<div class="list-property-name">{{ name }}</div>
<div>{{ row[name] }}</div>
</div>
</div>
</div>
</div>
I tried to implement the list and the grid view, Where I need to toggle between each one. For that i have taken isGrid and isList set to true, And from vue side i am trying to place ternary operator, And switch between each other.
Can you please help me on toggle from the list and grid view.
When you create a component whose view can be changed, I suggest that you use the container-presentational component pattern. Really easy to keep track, and it's a breeze to add a new "view" of the data.
// this is the grid view
// this is a presentational component:
// only displays what is passed through props
Vue.component("GridView", {
props: ["users"],
computed: {
headers() {
if (!this.users.length) return []
return Object.keys(this.users[0])
},
},
template: `
<table>
<thead>
<tr>
<th
v-for="header in headers"
:key="header"
>
{{ header }}
</th>
</tr>
</thead>
<tbody>
<tr
v-for="user in users"
:key="user.id"
>
<td
v-for="(val, key) in user"
:key="user.id + '-' + key"
>
{{ val }}
</td>
</tr>
</tbody>
</table>
`
})
// this is the list view
// this is a presentational component:
// only displays what is passed through props
Vue.component("ListView", {
props: ["users"],
template: `
<ol>
<li
v-for="user in users"
:key="user.id"
>
<div
v-for="(val, key) in user"
:key="user.id + '-' + key"
>
{{ key }}: {{ val }}
</div>
</li>
</ol>
`
})
// this component handles the data:
// fetching, mapping, transforming, etc.
// this is a renderless component
Vue.component("DataContainer", {
data() {
return {
users: []
}
},
mounted() {
this.fetchUsers()
},
methods: {
async fetchUsers() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users')
const json = await response.json()
this.users = json.map(({
id,
name,
username,
email
}) => ({
id,
name,
username,
email
}))
} catch (err) {
console.error(err)
}
}
},
render(h) {
// renders nothing, just provides the data
// by passing it through "users"
return this.$scopedSlots.default({
users: this.users,
})
},
})
// the Vue instance
new Vue({
el: "#app",
data() {
return {
layout: "list-view",
}
},
methods: {
switchView() {
this.layout = this.layout === "list-view" ? "grid-view" : "list-view"
}
},
template: `
<div>
<button
#click="switchView"
>
SWITCH VIEW
</button>
<data-container>
<template
#default="{ users }"
>
<component
:is="layout"
v-bind="{ users }"
/>
</template>
</data-container>
</div>
`,
})
table {
border-collapse: collapse;
}
table,
tr,
th,
td {
border: 1px solid black;
}
td,
th {
padding: 4px 8px;
}
th {
background-color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12/dist/vue.js"></script>
<div id="app"></div>
I understand that this is a bit further away from correcting a v-if condition-handling - but this setup would help you create flexible, extensible & maintainable solution.
I this is the cleanest solution
<template>
<button #click="toggleList">switch render view</button>
<component
:is="currentComponent"
:columns="gridData.columns"
:items="gridData.data"
/>
</template>
<script>
import gridComponent from "./your-grid-component.vue";
import listComponent from "./your-list-component.vue";
export default {
components: {
gridComponent,
listComponent,
},
data() {
return {
listType: "grid", //grid/list
gridData: {
columns: [],
data: [],
},
};
},
methods: {
toggleList() {
this.listType = this.listType === "grid" ? "list" : "grid";
},
},
computed: {
currentComponent() {
return this.listType === "grid" ? "gridComponent" : "listComponent";
},
},
};
</script>
I'm working on a filtering feature in a Vue application. I'm new to Vue, and I have the filter semi-working. It successfully allows me to select an asset type from the dropdown, and will filter the results accordingly. But what's not working is the clearFilters method.
My goal is to reset the assetType to an empty string and the filterResults array to empty, and my thought was that since checking the length of filterResults, when I clear it it would return to displaying the entire un-filtered array.
What am I doing wrong? Any information would be greatly appreciated.
<template>
<div ref="content">
<div class="container pt-3 text-center">
<div class="filter-container">
<div class="btn-group">
<button
v-ripple="'rgba(255, 255, 255, .2)'"
#click="showAssetType = !showAssetType"
class="btn btn-secondary dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
style="max-height: 40px;">
{{assetType ? assetType : 'Asset Type'}}
</button>
<div class="dropdown-menu" :style="'display:' + (showAssetType ? 'block' : 'none') + ';'">
<a class="dropdown-item" #click.prevent="setAssetFilter('all')" href="#!">All Assets</a>
<a class="dropdown-item" #click.prevent="setAssetFilter('USD'); filterByAssetType()" href="#!">USD</a>
<a class="dropdown-item" #click.prevent="setAssetFilter('GBP'); filterByAssetType()" href="#!">GBP</a>
<a class="dropdown-item" #click.prevent="setAssetFilter('CAD'); filterByAssetType()" href="#!">CAD</a>
</div>
</div>
</div>
</div>
<div id="data-table" v-if="filterResults.length > 0">
<div v-for="(transaction, index) in filterResults" :key="index">
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(transaction.date)}}</h1>
<div class="transaction-header-wrapper">
<p class="transaction-text">{{formatString(transaction.tx_type)}} Transaction</p>
<p class="transaction-text" style="text-align: right">{{transaction.coin_type}}</p>
</div>
</template>
<template v-slot:content>
<global-transaction :transaction='transaction' #updateClassType="updateClassType" />
</template>
</global-history-item>
</div>
</div>
<div id="data-table">
<div v-for="(item, index) in totalHistory" :key="index">
<div v-if="item.tx_type">
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(item.date)}}</h1>
<div class="transaction-header-wrapper">
<p class="transaction-text">{{formatString(item.tx_type)}} Transaction</p>
</div>
</template>
<template v-slot:content>
<global-transaction :transaction='item' #updateClassType="updateClassType" />
</template>
</global-history-item>
</div>
<div v-else-if="item.invoice_id">
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(item.date)}}</h1>
<div class="invoice-header-wrapper">
<p class="invoice-text">Invoice Created</p>
<p class="invoice-text">Invoice #{{item.invoice_id}}</p>
</div>
</template>
<template v-slot:content>
<global-invoice :invoice='item' />
</template>
</global-history-item>
</div>
<div v-else>
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(item.date)}}</h1>
<div class="invoice-header-wrapper">
<p class="invoice-text">Login Event</p>
<br />
</div>
</template>
<template v-slot:content>
<global-account-activity :message='"A successful login to your account was made"' />
</template>
</global-history-item>
</div>
</div>
</div>
</div>
</template>
<script>
... imports removed for brevity
export default {
name: 'Global',
components: { },
props: ['totalHistory', 'printFormat'],
mixins: ['formatDate', 'formatMenuLabel'],
data () {
return {
showAssetType: false,
showClassType: false,
activityType: '',
assetType: '',
filterResults: [],
printMode: false
}
},
methods: {
setAssetFilter (value) {
this.showAssetType = false
this.assetType = value
},
formatString (str) {
const firstLetter = str.charAt(0)
const remainder = str.slice(1)
return firstLetter.toUpperCase() + remainder
},
updateClassType (transactionRecord) {
this.$store.dispatch('updateTransactionType', transactionRecord)
},
updateTransaction (transactionRecord) {
console.log('in updateTransaction', transactionRecord)
this.$store.dispatch('updateTransactionNote', transactionRecord)
},
filterByAssetType () {
const selectedCurrency = this.assetType
if (this.assetType === 'all') {
this.clearFilters()
} else {
this.filterResults = this.totalHistory.filter(function (trans) {
return trans.currency === selectedCurrency
})
}
},
clearFilters () {
return (this.assetType = '') && (this.filterResults = [])
}
}
}
</script>
So if I am not mistaking, you only want the method clearFilters, to work? If so, try:
clearFilters () {
this.assetType = ''
this.filterResults = []
}
The logical AND operator (&&) is not to chain expressions. It’s to do an expression if the first expression is truthy.
First expression && second expression, example
const questionAnswered = true
console.log(questionAnswered && "Hooray!")
// will log "Hooray!" (Expression 2)
If you set questionAnswered to false, it will log false (expression 1)
I agree with Jens rewrite of clearFilters(). The original looked odd to me.
I had started creating a sample component to demonstrate possibly simplifying the filtering process when there were no answers. Since I have finished it and it works, I am posting it.
ClearFilters.vue
<template>
<div class="clear-filters">
<div class="row">
<div class="col-md-6">
<table class="table table-bordered">
<thead>
<tr>
<th>NAME</th>
<th>CURRENCY</th>
</tr>
</thead>
<tbody>
<tr v-for="asset in filteredAssets" :key="asset.id">
<td>{{ asset.name }}</td>
<td>{{ asset.currency }}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="criteria-label">FILTER CRITERIA:</label>
<select class="form-control" v-model="currentCriteria">
<option v-for="(criteria, index) in criteriaOptions" :key="index" :value="criteria">{{ criteria }}</option>
</select>
</div>
<button type="button" class="btn btn-secondary" #click="resetFilter">Reset</button>
</div>
</div>
</div>
</template>
<script>
import assets from './clear-filters-data.js';
export default {
data() {
return {
assets: assets,
criteriaOptions: [
'ALL', 'USD', 'GBP', 'CAD'
],
currentCriteria: 'ALL'
}
},
computed: {
filteredAssets() {
if (this.currentCriteria === 'ALL') {
return this.assets;
}
else {
return this.assets.filter( asset => asset.currency === this.currentCriteria);
}
}
},
methods: {
resetFilter() {
this.currentCriteria = 'ALL';
}
}
}
</script>
<style scoped>
.criteria-label {
font-weight: bold;
}
</style>
Test data:
const assets = [
{
id: 1,
name: 'asset1',
currency: 'USD'
},
{
id: 2,
name: 'asset2',
currency: 'USD'
},
{
id: 3,
name: 'asset3',
currency: 'USD'
},
{
id: 4,
name: 'asset4',
currency: 'GBP'
},
{
id: 5,
name: 'asset5',
currency: 'GBP'
},
{
id: 6,
name: 'asset6',
currency: 'GBP'
},
{
id: 7,
name: 'asset7',
currency: 'CAD'
},
{
id: 8,
name: 'asset8',
currency: 'CAD'
},
{
id: 9,
name: 'asset9',
currency: 'CAD'
},
]
export default assets;
I'm having issues loading two modals (openModalEdit and openModalDetail method) on my Angular 9 project. When I open it, it automaticly navigates to the root route.
I have another instance (openModalCreate method) of a modal in the same component, apparently both are the same changing only a couple of parameters like the modal title, but the first navigates and the other stays in the modal.
You get to see the modal appearing just before the navigation moves to the root route and the OnInit method of the modal component doesn't have any code, so the modal component doesn't have any functionality that can provoke the navigation in any point.
My bootstrap installed version is "#ng-bootstrap/ng-bootstrap": "^6.0.3".
Does anyone know how to prevent navigation on NgbModal load?
Codebehind:
emitIconButtonClick (action, i, content) {
switch (action) {
case 'edit':
this.openModalEdit(i);
break;
case 'delete':
this.onDeleteRow(i);
break;
case 'detail':
this.openModalDetail(i, content);
break;
default:
break;
}
}
openModalCreate () {
this._formsService.editing = false;
const modalRef = this.modalService.open(DynamicModalComponent, {
size: 'lg',
});
modalRef.componentInstance.title = 'Nuevo ' + this.config.label;
modalRef.componentInstance.fields = this.config.fields;
modalRef.componentInstance.close.subscribe(() => {
modalRef.close();
});
modalRef.componentInstance.save.subscribe((event) => {
this._formsService.setSavedStatusForm(false);
this.rows.push(event);
this.bindToForm();
modalRef.close();
});
}
openModalEdit (index: number) {
const modalRef = this.modalService.open(DynamicModalComponent, {
size: 'lg',
});
modalRef.componentInstance.title = 'Editar ' + this.config.label;
modalRef.componentInstance.fields = this.config.fields;
modalRef.componentInstance.data = this.rows[index];
modalRef.componentInstance.close.subscribe(() => {
modalRef.close();
});
modalRef.componentInstance.save.subscribe((event) => {
this.rows[index] = event;
this._formsService.setSavedStatusForm(false);
this.bindToForm();
modalRef.close();
});
}
openModalDetail (i: number, content: any) {
this.detailArray = [];
Object.entries(this.rows[i]).forEach((e) => {
const entry = {
name: e[0],
value: e[1],
};
this.detailArray.push(entry);
});
this.modalService.open(content).result.then(
(result) => { debugger },
(reason) => { debugger }
);
}
HTML
<div class="form-group dynamic-group field" [formGroup]="group">
<div class="add-btn">
<app-button (click)="openModalCreate()" clasesBtn="btn-primary" icono="plus-circle"> </app-button>
</div>
<div [attr.id]="config.name" [attr.name]="config.name" class="master-table">
<table class="table table-striped">
<thead>
<tr>
<th *ngFor="let header of config.fields" scope="col">
{{ (header.header ? header.header : header.name) | translate }}
</th>
<th *ngIf="config.actions">
{{ 'actions' | translate }}
</th>
</tr>
</thead>
<tbody [ngSwitch]="true">
<tr *ngFor="let row of rows; index as i">
<td *ngFor="let header of config.fields">
<div class="ellipsis max-width-cell">
{{ showDataTable(row[header?.name], header.name) }}
</div>
</td>
<td *ngIf="config.actions">
<div class="table-body_row_actions">
<a *ngFor="let action of config.actions" href="" (click)="emitIconButtonClick(action.name, i, content)" [ngClass]="{
'table-body_row_actions-container': true,
delete: action.name === 'delete'
}">
<i-feather name="{{ action.icon }}" class="feather-icon"></i-feather>
</a>
</div>
</td>
<ng-template #content let-modal>
<div class="modal-header">
<h4 class="modal-title">
{{ 'detail' | translate }}
</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body custom-modal-body">
<div class="flex-container">
<div class="dataCell" *ngFor="let field of detailArray">
<div class="header">
{{ field.name | translate }}
</div>
<div class="data">
{{ showDataTable(field.value, field.name) }}
</div>
</div>
</div>
</div>
</ng-template>
</tr>
</tbody>
</table>
</div>
</div>
RESOLVED by #zainhassan
--> Remove href="" from a tag
I'm trying to use this code hosting on Firebase, but it doesn't work. {{Item.name}} appears instead of the value :(
I already tested the same code on Codepen and it worked. Does the firebase accept vue.min.js?
When deploying, the site displays the {{var}} instead of the table value in Google Sheets.
I'm trying to use this code hosting on Firebase, but it doesn't work. {{Item.name}} appears instead of the value :(
I already tested the same code on Codepen and it worked. Does the firebase accept vue.min.js?
When deploying, the site displays the {{var}} instead of the table value in Google Sheets.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script>
var app = new Vue({
el: '#app',
mounted() {
let vm = this
axios
.get(
'https://sheets.googleapis.com/v4/spreadsheets/{sheetsID}/values/A2:C20?key={apiKey}'
)
.then(function (response) {
let specials = response.data.values
for (let index = 0; index < specials.length; index++) {
const element = specials[index]
let mitem = {
name: element[0],
description: element[1],
price: element[2]
}
if (vm.isEven(index)) {
vm.menuItems_L = vm.menuItems_L.concat(mitem)
} else {
vm.menuItems_R = vm.menuItems_R.concat(mitem)
}
}
console.log(response)
})
},
data: {
menuItems_L: [],
menuItems_R: [],
menuStyle: {
background: '#f2f2f2',
color: '#000'
}
},
computed: {},
methods: {
isEven: function (n) {
return n % 2 == 0
}
}
});
</script>
<body>:
<div id="app">
<section id="specialssection" class="specials-container" v-if="menuItems_L" :style="menuStyle">
<div id="special_component" :style="menuStyle">
<div class="specials-table-container">
<table>
<tbody v-for="item in menuItems_L" :key="item.name">
<tr class="nameandprice">
<td>
<span :style="menuStyle">{{item.name}}</span>
</td>
<td>
<span :style="menuStyle">R${{item.price}}</span>
</td>
</tr>
<tr class="description">
<td colspan="2">{{item.description}}</td>
</tr>
</tbody>
</table>
<table>
<tbody v-for="item in menuItems_R" :key="`specialmenu-${item.name}`">
<tr class="nameandprice">
<td>
<span :style="menuStyle">{{item.name}}</span>
</td>
<td>
<span :style="menuStyle">${{item.price}}</span>
</td>
</tr>
<tr class="description">
<td colspan="2">{{item.description}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</div>
It looks like the only thing wrong is the order of the tags.
You just need to run the vue code after the <div id="app"> tag is loaded into the DOM. Here's an example:
<html>
<head>
<!-- Include all CDN scripts here -->
</head>
<body>
<div id="app" >
</div>
<script>
// Needs to be called after the <div id="app"> tag is loaded into the DOM
var app = new Vue({
el: '#app',
...
})
</script>
</body>
</html>