Vue.js remove item in arrray - javascript

1.i want to remove Link in the method from a vue.js component
please helm me..error in console is method splice is undefined.
link will add when the message in insert.message is not a problem.
insert link in not a problem.but it's not possible to remove.
push array in my single page.but if is not good for the user is possible to remove
<div class="list-group">
<div class="col-lg-4" style="margin-
top:3px">
<input type="text" v-model="link.title"
class="form-control" placeholder="titolo" id="title">
</div>
<div class="col-lg-7">
<input type="text" v-model="link.hyperlink"
class="form-control" placeholder="link" id="link">
</div>
<div class="col-lg-1">
<button #click="addLink" type="button"
id="add-link-btn" class="btn btn btn-primary pull-
right">+</button>
</div>
</div>
</div>
<div v-for="link in message.links"
:key="link.id">
<div class="row">
<div class="col-lg-6">
<p>{{link.title}}</p>
</div>
<div class="col-lg-6">
<a>{{link.hyperlink}}</a>
<button class="btn btn-xs btn-danger"
#click="removeLink(link)">Delete</button>
</div>
</div>
<scrip>
data() {
return {
title: "Aggiungi",
link: {
id: 1,
autore: "Amedeo",
title: "",
hyperlink: ""
},
}
}
methods: {
addMessage() {
var id = this.messages.length
? this.messages[this.messages.length - 1].id
: 0;
var message = Object.assign({}, this.message);
message.id = id + 1;
message.date = new Date();
this.messages.push(message);
this.message.title = "";
this.message.subtitle = "";
this.message.body = "";
},
// metodo addlink che inserisci un nuovo link ovvimente lavorando
sul id del messaggio padre
addLink() {
var messageId = this.messages.length
? this.messages[this.messages.length - 1].id
: 1;
var id = this.message.links.length
? this.message.links[this.message.links.length - 1].id
: parseInt(messageId + "0", 10);
var link = Object.assign({}, this.link);
link.id = id + 1;
link.date = new Date();
this.message.links.push(link);
this.link.title = "";
this.link.hyperlink = "";
},
removeLink(link) {
this.links.splice(this.links.indexOf(link), 1);
}
}
};

You need to pre-define every property you will access in data.
Due to the limitations of modern JavaScript (and the abandonment of
Object.observe), Vue cannot detect property addition or deletion.
https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
In your code messages and links are not defined in your data object at the start, so the reactivity will not work.
For example, the following code doesn't work :
<div id="app">
Message: {{message}}<br />
<input type="text" v-on:input="update($event.target.value)" />
</div>
<script>
new Vue({
el: '#app',
data: {
},
methods: {
update: function(value) {
this.message = value;
}
}
});
</script>
https://jsfiddle.net/m4q44g7f/
But this code works because message is defined at the start.
<div id="app">
Message: {{message}}<br />
<input type="text" v-on:input="update($event.target.value)" />
</div>
<script>
new Vue({
el: '#app',
data: {
message: ''
},
methods: {
update: function(value) {
this.message = value;
}
}
});
</script>
https://jsfiddle.net/m4q44g7f/1/
Note: There might be other errors in your code but you first need to fix this one.

Related

VUE JS - Some of my methods are being called without me calling them

I'm having an annoying issue with Vue JS >.< My methods are being called without my approval. I basically have a button that execute a method, but this method execute when other methods are executed, making it very annoying...
Here is my form
<form class="row">
<div class="col-xl-6 col-lg-6 col-md-6 col-sm-12 col-12 pr-xl-0 pr-lg-0 pr-md-0 m-b-30">
<div class="product-slider">
<img class="d-block" :src="image" alt="First slide" width="285" height="313">
Image URL <input type="text" #focusout="showPicture" id="imageLink">
</div>
</div>
<div class="col-xl-6 col-lg-6 col-md-6 col-sm-12 col-12 pl-xl-0 pl-lg-0 pl-md-0 border-left m-b-30">
<div class="product-details">
<div class="border-bottom pb-3 mb-3">
<h2 class="mb-3">
<input type="text" value="Product Name" minlength="4" id="name" required/>
</h2>
<h3 class="mb-0 text-primary">$<input type="number" value="1.00" step="0.01" id="price" required></h3>
</div>
<div class="product-size border-bottom">
<h4>Provider</h4>
<input type="text" value="Pro Inc." minlength="3" id="provider" required>
<div class="product-qty">
<h4>Quantity</h4>
<div class="quantity">
<input type="number" value="1" id="quantity" required>
</div>
</div>
</div>
<div class="product-description">
<h4 class="mb-1">Description</h4>
<textarea rows="4" cols="50" minlength="50" id="description" required>Sample Text</textarea>
<button :onclick="addProduct()" class="btn btn-primary btn-block btn-lg">Add to inventory</button>
</div>
</div>
</div>
</form>
and here is my full script
<script>
const DB_NAME = 'DBInventory';
const DB_VERSION = 1;
export default {
data: function() {
return {
db:null,
ready:false,
addDisabled:false,
image: "https://i.imgur.com/O9oZoje.png",
};
},
async created() {
this.db = await this.getDb();
this.ready = true;
},
methods: {
showPicture() {
let link = document.getElementById("imageLink").value;
if(link !== "")
this.image = link;
},
async getDb() {
return new Promise((resolve, reject) => {
let request = window.indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = e => {
console.log('Error opening db', e);
reject('Error');
};
request.onsuccess = e => {
resolve(e.target.result);
};
request.onupgradeneeded = e => {
console.log('onupgradeneeded');
let db = e.target.result;
let objectStore = db.createObjectStore("products", { autoIncrement: true, keyPath:'id' });
console.log(objectStore);
};
});
},
async addProduct() {
this.addDisabled = true;
let product = {
name: document.getElementById("name").value,
provider: document.getElementById("provider").value,
price: document.getElementById("price").value,
quantity: document.getElementById("quantity").value,
description: document.getElementById("description").value,
image: document.getElementById("imageLink").value,
};
console.log('about to add '+JSON.stringify(product));
await this.addProductToDb(product);
this.addDisabled = false;
},
async addProductToDb(product) {
return new Promise((resolve, reject) => {
//delete me
console.log(reject);
let trans = this.db.transaction(['products'],'readwrite');
trans.oncomplete = e => {
//delete me
console.log(e);
resolve();
};
let store = trans.objectStore('products');
store.add(product);
});
},
}
}
</script>
One of my method execute when you are not focused on the image input field. It works, but also execute the addProduct(), which push my item to my indexDB, something that I want to happen only when I press the button "Add to inventory".
This is very confusing and I'm kinda a noob on Vue JS ^^' (I use Vue 3)
You have the wrong syntax
:onclick="addProduct()"
:onclick should be #click or v-on:click
https://v2.vuejs.org/v2/guide/events.html
To avoid the function to be autoexecuted, you need to provide the onclick method with the function declaration. Try the code below. I don't use Vue, but it works in React. Javascript anyway.
:onclick="() => addProduct()"
Correct syntax for click event in vue
full syntax
<a v-on:click="addProduct"></a>
shorthand syntax
<a #click="addProduct"></a>
Then call method addProduct
addProduct: function () {
...
}

how to get pre filled data in input type in vue js

i have chuck of code in vue js.. I am not able to get value from input
here is my code
HTML Codes:
<div id = "app">
<div class="form-group">
<input type="text" class="form-control" name = "name" value = "lorem" v-model = "name"/>
</div>
<button class="btn btn-primary btn-block" v-on:click="sendData()">SIGN UP</button>
</div>
Vue js codes:
<script>
var app = new Vue({
el: "#app",
data() {
errors :{}
return {
input: {
name: "",
},
}
},
methods: {
sendData() {
alert(this.name);
}
}
})
Thanks
As the declare for the data properties, uses v-model="input.name", then alert(this.input.name).
If you'd like to assign default value for the input, decalre the data property like {input:{name: 'lorem'}}.
var app = new Vue({
el: "#app",
data() {
errors: {}
return {
input: {
name: "", // or pre-fill with other default value like `lorem`
},
}
},
methods: {
sendData() {
alert(this.input.name);
}
}
})
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<div class="form-group">
<input type="text" class="form-control" name="name" value="lorem" v-model="input.name" />
</div>
<button class="btn btn-primary btn-block" v-on:click="sendData()">SIGN UP</button>
</div>
Use v-model only, without value attribute:
<div id = "app">
<div class="form-group">
<input
type="text"
class="form-control"
name="name"
v-model="name"
/>
</div>
<button
class="btn btn-primary btn-block"
#click="sendData"
>
SIGN UP
</button>
</div>
<script>
var app = new Vue({
el: "#app",
data () {
return {
name: 'lorem'
}
},
methods: {
sendData () {
alert(this.name)
}
}
})
</script>

Initialise canvas for every Vue.JS template loop

I'm stuck trying to work out how to initialize a local "signaturePad" canvas for every loop / signature required.
I'm also keen to bind "dataURL" to signaturePad.toDataURL("image/jpg"). I.e. show the dataURI for each signature entered.
Hope you can help! Here's the JSfiddle too: https://jsfiddle.net/kaihendry/kt53sa2r/1/
// var canvas = document.querySelector("canvas");
// var signaturePad = new SignaturePad(canvas);
// var wrapper = document.getElementById("signature-pad");
// How do I initialise signaturePad for every signatureNeeded?
new Vue({
el: "#app",
data: {
signaturesNeeded: 2,
},
methods: {
submitForm: function(x) {
fetch('/echo/html', {
method: 'POST',
body: new FormData(x.target)
})
.then(() => {
var button = document.getElementById("button")
button.innerText = 'Sent!'
})
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/signature_pad#2.3.2/dist/signature_pad.min.js"></script>
<div id="app">
<label>Number of signatures required
<input type=number v-model.number="signaturesNeeded">
</label>
<form id="myForm" v-on:submit.prevent="submitForm">
<template v-for="item in signaturesNeeded">
<div class="signature-pad">
<div class="signature-pad--body">
<canvas></canvas>
</div>
<div class="signature-pad--footer">
<div class="description">Sign above</div>
</div>
<input required type=text size=80 placeholder="Name" name=name>
<input required type=text size=80 name=dataURL>
</template>
<button class="button" id="button" type="submit">Sign</button>
</form>
Signature pad sources
</div>
You can define custom component (signature-pad for example) and initialize SignaturePad there. I created working snippet below. It also update signature data url when user stops writing(it shows below the canvas) and as example all urls are collected by parent component. Check it:
Vue.component('signature-pad', {
template: '#signaturepad',
data() {
return {
signaturePad: null,
dataUrl: null
}
},
mounted() {
this.signaturePad = new SignaturePad(this.$refs.canv, {
onEnd: () => {
this.dataUrl = this.signaturePad.toDataURL();
// as example collect all url in parent
this.$emit('update', this.dataUrl)
}
});
}
});
new Vue({
el: "#app",
data: {
signaturesNeeded: 2,
// all signature urls as example
signatureDataUris: []
},
methods: {
submitForm: function (x) {
fetch('/echo/html', { method: 'POST',
body: new FormData(x.target) })
.then(() => {
var button = document.getElementById("button")
button.innerText = 'Sent!'
})
},
updateSignature(index, url) {
Vue.set(this.signatureDataUris, index, url);
console.log(this.signatureDataUris);
}
}
})
<script src="https://cdn.jsdelivr.net/npm/signature_pad#2.3.2/dist/signature_pad.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<label>Number of signatures required
<input type=number v-model.number="signaturesNeeded">
</label>
<form id="myForm" v-on:submit.prevent="submitForm">
<template v-for="item in signaturesNeeded">
<signature-pad #update="(val) => updateSignature(item-1, val)" ></signature-pad>
<input required type=text size=80 placeholder="Name" name=name>
</template>
<button class="button" id="button" type="submit">Sign</button>
</form>
Signature pad sources
</div>
<script type='text/x-template' id="signaturepad">
<div class="signature-pad">
<div class="signature-pad--body">
<canvas ref="canv"></canvas>
<div>{{dataUrl}}</div>
</div>
<div class="signature-pad--footer">
<div class="description">Sign above</div>
</div>
</div>
</script>

Aurelia issue with setting element class based on obj.id === $parent.selectedId

I completed the contact-manager tut from Aurelia.io and am incorporating it into as task manager tut I'm putting together. The markup below sets the li class based on task.id === $parent.id.
task-list.html
<template>
<div class="task-list">
<ul class="list-group">
<li repeat.for="task of tasks" class="list-group-item ${task.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: tasks; params.bind: {id:task.id}" click.delegate="$parent.select(task)">
<h4 class="list-group-item-heading">${task.name}</h4>
<span class="list-group-item-text ">${task.due | dateFormat}</span>
<p class="list-group-item-text">${task.isCompleted}</p>
</a>
</li>
</ul>
</div>
task-list.js
#inject(WebAPI, EventAggregator)
export class TaskList {
constructor(api, ea) {
this.api = api;
this.tasks = [];
ea.subscribe(TaskViewed, x => this.select(x.task));
ea.subscribe(TaskUpdated, x => {
let id = x.task.id;
let task = this.tasks.find(x => x.id == id);
Object.assign(task, x.task);
});
}
created() {
this.api.getList().then( x => this.tasks = x);
}
select(task) {
this.selectedId = task.id;
return true;
}
}
If I edit the current task, represented by
task-detail.html
<template>
<require from="resources/attributes/DatePicker"></require>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Edit Task Profile</h3>
</div>
<div class="panel-body">
<form role="form" class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-10">
<input type="text" placeholder="name" class="form-control" value.bind="task.name">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description</label>
<div class="col-sm-10">
<input type="text" placeholder="description" class="form-control" value.bind="task.description">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Due Date</label>
<div class="col-sm-10">
<div class="input-group date">
<input type="text" datepicker class="form-control" value.bind="task.due | dateFormat:'L'"><span class="input-group-addon"><i class="glyphicon glyphicon-th"></i></span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Urgency</label>
<div class="col-sm-10">
<input type="range" min="1" max="5" step="1" class="form-control" value.bind="task.urgency">
</div>
</div>
</form>
</div>
</div>
<div class="button-bar">
<button class="btn btn-info" click.delegate="addTask(task)" >Add New</button>
<button class="btn btn-success" click.delegate="save()" disabled.bind="!canSave">Save Edit</button>
</div>
</template>
task-detail.js
#inject(WebAPI, EventAggregator, Utils, DialogService)
export class TaskDetail {
constructor(api, ea, utils, dialogService) {
this.api = api;
this.ea = ea;
this.utils = utils;
this.dialogService = dialogService;
}
activate(params, routeConfig) {
this.routeConfig = routeConfig;
return this.api.getTaskDetails(params.id).then(task => {
this.task = task;
this.routeConfig.navModel.setTitle(task.name);
this.originalTask = this.utils.copyObj(task);
this.ea.publish(new TaskViewed(task));
});
}
get canSave() {
return this.task.name && !this.api.isRequesting;
}
save() {
console.log(this.task);
this.api.saveTask(this.task).then(task => {
this.task = task;
this.routeConfig.navModel.setTitle(task.name);
this.originalTask = this.utils.copyObj(task);
this.ea.publish(new TaskUpdated(this.task));
});
}
canDeactivate() {
if (!this.utils.objEq(this.originalTask, this.task)) {
let result = confirm('You have unsaved changes. Are you sure you wish to leave?');
if (!result) {
this.ea.publish(new TaskViewed(this.task));
}
return result;
}
return true;
}
addTask(task) {
var original = this.utils.copyObj(task);
this.dialogService.open({viewModel: AddTask, model: this.utils.copyObj(this.task)})
.then(result => {
if (result.wasCancelled) {
this.task.name = original.title;
this.task.description = original.description;
}
});
}
}
If a value has changed, navigation away from the current task is not allowed, and that works -- that is, the contact-detail part of the UI doesn't change. However, the task <li>, that one tries to navigate to still gets the active class applied. That's not supposed to happen.
If I step along in dev tools, on the Aurelia.io contact-manager, I see that the active class is briefly applied to the list item, then it goes away.
from the contact-manager's contact-list.js This was run when clicking an <li> and no prior item selected.
select(contact) {
this.selectedId = contact.id;
console.log(contact);
return true;
}
This logs
Object {__observers__: Object}
Object {id: 2, firstName: "Clive", lastName: "Lewis", email: "lewis#inklings.com", phoneNumber: "867-5309"}
The same code on my task-manager's (obviously with "contact" replaced by task") task-list.js logs
Object {description: "Meeting With The Bobs", urgency: "5", __observers__: Object}
Object {id: 2, name: "Meeting", description: "Meeting With The Bobs", due: "2016-09-27T22:30:00.000Z", isCompleted: falseā€¦}
My first instinct is to say it's got something to do with this.selectedId = contact.id
this there would refer to what I assume is a function called select (looks like the function keyword is missing in your example?) or the global object (i.e. window)
select(contact) {
this.selectedId = contact.id;
console.log(contact);
return true;
}
Fixed it. It wasn't working because I had pushstate enabled. That clears things up. Thanks therealklanni.

How to implement paging in "with" bindings in knockout

I have a requirements in my project where I need to put my selected item in the Modal and user can click next to show the next item.
I am using a with binding to display the content of selected in a form. I don't have an idea on how can I apply paging inside a "With" binding.
<div class="container" data-bind="with: itemForEditing">
<div id="riskRegisterForm" class="modal hide fade">
<div class="modal-header" style="background:#4bafef; height: 30px;">
<h5 style="color:#FFFFFF; font:16px Arial;">Item</h5>
</div>
<div class="modal-body" style="background:#fff">
<div>
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="itemName">Name</label>
<div class="controls">
<input type="text" id="itemName" data-bind="value: name" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="itemPrice">Price</label>
<div class="controls">
<input type="number" step=".01" id="itemPrice" data-bind="value: price" />
</div>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" class="btn" data-bind="click:$parent.revertItem">Cancel</button>
<button type="button" data-dismiss="modal" class="btn" data-bind="click:$parent.acceptItem">Update</button>
</div>
<span><a href=#>next</a></span>
<span><a href=#>prev</a></span>
</div>
</div>
when I click the next it should autmatically select the next records and put in the contorls. Here is the JsFiddle http://jsfiddle.net/ramon26cruz/Tt96J/6/
I've had a go at this. I changed my tack from above. Basically I created 2 method, a next and a prev. In the methods I find the index of the selected / editable object in the array and the either increment or decrement based on which method has been used. I then update the selected and editable property objects:
var Item = function(data) {
this.name = ko.observable();
this.price = ko.observable();
//populate our model with the initial data
this.update(data);
};
//can pass fresh data to this function at anytime to apply updates or revert to a prior version
Item.prototype.update = function(data) {
this.name(data.name || "new item");
this.price(data.price || 0);
};
var ViewModel = function(items) {
this.index = 0;
//turn the raw items into Item objects
this.items = ko.observableArray(ko.utils.arrayMap(items, function(data) {
return new Item(data);
}));
//hold the currently selected item
this.selectedItem = ko.observable();
//make edits to a copy
this.itemForEditing = ko.observable();
this.selectItem = this.selectItem.bind(this);
this.acceptItem = this.acceptItem.bind(this);
this.revertItem = this.revertItem.bind(this);
this.next = this.next.bind(this);
this.prev = this.prev.bind(this);
};
ko.utils.extend(ViewModel.prototype, {
//select an item and make a copy of it for editing
selectItem: function(item) {
this.selectedItem(item);
this.itemForEditing(new Item(ko.toJS(item)));
},
next:function(){
var pos = this.items.indexOf(this.selectedItem()) + 1;
if(pos > this.items().length - 1){pos = 0};
this.selectedItem(this.items()[pos]);
this.itemForEditing(new Item(ko.toJS(this.items()[pos])));
},
prev:function(){
var pos = this.items.indexOf(this.selectedItem()) - 1;
if(pos < 0){pos = this.items().length - 1};
this.selectedItem(this.items()[pos]);
this.itemForEditing(new Item(ko.toJS(this.items()[pos])));
},
acceptItem: function(item) {
var selected = this.selectedItem(),
edited = ko.toJS(this.itemForEditing()); //clean copy of edited
//apply updates from the edited item to the selected item
selected.update(edited);
//clear selected item
this.selectedItem(null);
this.itemForEditing(null);
},
//just throw away the edited item and clear the selected observables
revertItem: function() {
this.selectedItem(null);
this.itemForEditing(null);
}
});
ko.applyBindings(new ViewModel([
{ name: "Cheese", price: 2.50 },
{ name: "Pepperoni", price: 3.25 },
{ name: "Deluxe", price: 4.25 }
]));
Here's a link to my JS Fiddle.
One way to do it would be like this:
<div class="container" data-bind="with: itemForEditing">
<!-- ... -->
<span>next</span>
<span>prev</span>
</div>
and
ko.utils.extend(ViewModel.prototype, {
// offset the selected item by a certain amount (i.e. -1/+1 for next/prev)
offsetItem: function (by) {
var items = this.items(),
i = ko.utils.arrayIndexOf(items, this.selectedItem()),
newItem = (i > -1) ? items[i + by] : null;
if (newItem) {
this.selectItem(newItem);
}
},
prevItem: function () {
this.offsetItem(-1);
},
nextItem: function () {
this.offsetItem(1);
},
/* ... */
}
See it live http://jsfiddle.net/Tt96J/11/

Categories