Changing from String to Array in AngularJS - javascript

I'm building an app to store records in LocalStorage.
Each record is an object in an array, and each record contains multiple objects. The object looks like this:
$scope.recordlist.push(
{
date: $scope.dateJson,
time: $scope.time,
car: $scope.carList.code,
driver: $scope.driverList.name,
from: $scope.locationList.place,
destination: $scope.locationList2.place,
pax: $scope.paxList,
comment: '',
commenttime: '',
arrival: '',
inserted: '',
cancelled:'',
duration:''
}
);
Right now, comment and commenttime are strings.
I create and edit them like this from the front-end:
<div class="col-md-1 msf-button">
<button class="btn-primary"
ng-init="inserted = true"
ng-click="editItem = !editItem"
ng-show="!record.arrival && !record.cancelled && !editItem">
<i class="fa fa-pencil"></i>
</button>
<button class="btn-success"
ng-click="commentTime(record); editItem = !editItem"
ng-show="!record.arrival && editItem && !record.cancelled">
<i class="fa fa-check"></i>
</button>
</div>
<div class="row msf-comment"
ng-show="editItem == true && !record.arrival"
ng-hide="!editItem">
<div class="col-md-12">
<input placeholder="Add a comment"
class="form-control"
ng-model="record.comment">
</div>
</div>
<div class="row msf-comment-row"
ng-show="!editItem && record.comment">
<div class="col-md-12">
<span class="caret"></span>
<span class="comment">
{{record.comment}} - {{record.commenttime}}
</span>
</div>
</div>
The first button will show the first row with the input (comment is added manually)
The second button will hide the input and display the comment, as well as adding commenttime (commentTime(record)):
$scope.commentTime = function (record){
record.commenttime = moment().format("HH.mm");
jsonToRecordLocalStorage($scope.recordlist);
};
The first button will allow to edit this comment, opening the input again and so on.
My problem is as follows: As of now, there's only one comment and one commenttime per record.
How could I manage to turn comment and commenttime into arrays?
I would like to add different comments and different commenttime, more like a checkpoint thing.
EDIT
Following the answer from Spasho I've gotten here:
$scope.recordlist = extractRecordJSONFromLocalStorage();
$scope.addRecord = function () {
$scope.recordlist.push(
{
date: $scope.dateJson,
time: $scope.time,
car: $scope.carList.code,
driver: $scope.driverList.name,
from: $scope.locationList.place,
destination: $scope.locationList2.place,
pax: $scope.paxList,
comment: [{
message: '',
commenttime: ''
}],
commenttime: '',
arrival: '',
inserted: '',
cancelled:'',
duration:''
}
);
$scope.custom = $scope.custom === false ? true: false;
$scope.carList = 0;
$scope.driverList = 0;
$scope.locationList = 0;
$scope.locationList2 = 0;
jsonToRecordLocalStorage($scope.recordlist);
$scope.editItem = false;
};
$scope.commentTime = function (record){
$scope.record.comment.push(
{
commenttime : moment().format("HH.mm")
}
);
jsonToRecordLocalStorage($scope.recordlist);
};
function jsonToRecordLocalStorage(recordlist) {
var jsonRecordlist = angular.toJson(recordlist);
if (jsonRecordlist != 'null') {
localStorage.setItem("recordspax", jsonRecordlist);
} else {
alert("Invalid JSON!");
}
}
But I run into trouble when I try to record data into comment.message and comment.commenttime.
This is the relevant Front end part:
<button class="btn-success"
ng-click="commentTime(record);">
<i class="fa fa-check"></i>
</button>
<div class="col-md-12">
<input placeholder="Add a comment"
class="form-control"
ng-model="record.comment.message">
</div>
<div class="col-md-12"
ng-repeat="comment in record.comment">
<span class="comment">
{{comment.message}} - {{comment.commenttime}}
</span>
</div>
The input with ng-model="record.comment.message" is supposed to store/display the comment, and the commentTime(record) function to store the time.
TypeError: Cannot read property 'comment' of undefined
This is what happens when I trigger commentTime(record) with some text (test) in the input model:
What am I missing?

change the model to make comment an array of objects, e.g.
$scope.recordlist.push(
{
date: $scope.dateJson,
time: $scope.time,
car: $scope.carList.code,
driver: $scope.driverList.name,
from: $scope.locationList.place,
destination: $scope.locationList2.place,
pax: $scope.paxList,
comments: [{
message: 'one comment',
date: new Date()
}],
arrival: '',
inserted: '',
cancelled:'',
duration:''
});
display the comments in an ng-repeat and change input bind
<div class="col-md-12">
<input placeholder="Add a comment"
class="form-control"
ng-model="commentMessage">
</div>
<div class="row msf-comment-row"
ng-show="!editItem && record.comment">
<div class="col-md-12" ng-repeat="comment in record.comments">
<span class="caret"></span>
<span class="comment">
{{comment.message}} - {{comment.date| date: 'yyyy-MM-dd'}}
</span>
</div>
</div>
change commentTime() accordingly
$scope.commentTime = function (record){
record.comment.push(
{
message: $scope.commentMessage,
commenttime : moment().format("HH.mm")
}
);
jsonToRecordLocalStorage($scope.recordlist);
};

Related

v-model not working with javascript functions

I am new to Vue JS and have been learning it from the documentation provided. My project is a simple task adding web-app. On using the v-model directive, I'm not getting any output. My javascript function to add the task is apparently not being called.
<template>
<div id="text">
TASKS:
<form onsubmit="return addTodo()">
<input type="text" class="todo-input" placeholder="What's up" v-model="message">
<input type="date" class="todo-input" v-model="ddate" >
<input type="submit" value="Add">
</form>
<div v-for="(todo, index) in todos" :key="todo.id" class="todo-item">
<div>
{{todo.id}}{{todo.title}}{{todo.date}}
</div>
</div>
</div>
</div>
</template>
export default {
name: 'todo-list',
data () {
return {
message: '',
ddate: '',
idForTodo: 1,
todos: [
]
}
},
methods: {
addTodo(){
if(this.message.trim().length == 0){
return
}
this.todos.push({
id: this.idForTodo,
title: this.message,
completed: false,
editing: false,
date: this.ddate,
})
this.ddate = ''
this.message = ''
this.idForTodo++
},
}
}
Looks like someone edited the question with correct code while I was writing the answer. I tried and tested same code in code snippet and it's working.
const app = new Vue({
el: '#text',
data() {
return {
message: '',
ddate: '',
idForTodo: 1,
todos: [
]
}
},
methods: {
addTodo(){
console.log(this.message)
if(this.message.trim().length == 0){
return
}
this.todos.push({
id: this.idForTodo,
title: this.message,
completed: false,
editing: false,
date: this.ddate,
})
this.ddate = ''
this.message = ''
this.idForTodo++
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
<div id="text">
TASKS:
<form>
<input type="text" class="todo-input" placeholder="What's up" v-model="message">
<input type="date" class="todo-input" v-model="ddate" >
<button v-on:click.prevent="addTodo">Add</button>
</form>
<div v-for="(todo, index) in todos" :key="todo.id" class="todo-item">
<div>
{{todo.id}} {{todo.title}} {{todo.date}}
</div>
</div>
</div>

Dynamic generated form with checkbox in Vue

I have dynamic generated form in Vue. Every loop have v-model. Everything work fine. But when I use checkboxes v-model work for all loops not on one like in input type text. Can You help me solved this problem? Below Vue code:
<fieldset>
<div class="form-row mb-2" v-for="input, index in journal" :key="index">
<div class="col-auto">
<label for="date">Data</label>
<Datepicker v-model="input.date" input-class="form-control" :input-attr="{id: 'date', name: 'date'}" style="width: 100%;" />
</div>
<div class="col-md-2">
<label for="timeStart">Od</label>
<Datepicker type="time" v-model="input.timeStart" format="HH:mm" input-class="form-control" :input-attr="{id: 'timeStart', name: 'timeStart'}" style="width: 100%;" />
</div>
<div class="col-md-2">
<label for="timeEnd">Do</label>
<Datepicker type="time" v-model="input.timeEnd" format="HH:mm" input-class="form-control" :input-attr="{id: 'timeEnd', name: 'timeEnd'}" style="width: 100%;" />
</div>
<div class="col-md-2">
<label for="players">Lista obecności</label>
<div class="form-check" v-for="item in input.players">
<input v-model="item.checked" type="checkbox" class="form-check-input" :id="'id-'+item.id+'set'+index">
<label class="form-check-label" :for="'id-'+item.id+'set'+index">{{ item.fullName }}</label>
</div>
</div>
<div class="col-auto">
<label for="description">Opis</label>
<textarea v-model="input.description" class="form-control" rows="7" id="description" placeholder="Opis"></textarea>
</div>
<div class="col-auto" #click="addInput" v-show="index == journal.length-1 && journal.length < 16">
<ButtonVue style="margin-top: 30px;" title="Dodaj" type="button" cancelWidth="true" color="btn-success"><i class="fas fa-plus"></i></ButtonVue>
</div>
<div class="col-auto align-self-start" #click="removeInput(index)" v-show="index || ( !index && journal.length > 1)">
<ButtonVue style="margin-top: 30px;" title="Usuń" type="button" cancelWidth="true" color="btn-danger"><i class="fas fa-minus"></i></ButtonVue>
</div>
</div>
</fieldset>
 
data() {
return {
contact: [],
journal: [{
date: "",
timeStart: "",
timeEnd: "",
players: "",
description: ""
}],
contacts: [],
}
},
Methods:
Method for creating dynamic form
addInput() {
this.journal.push({
date: "",
timeStart: "",
timeEnd: "",
players: this.contact,
description: ""
});
},
And here is the method which gets players from contacts
getContacts() {
this.pageLoader = true;
this.$http.get('/pkpar/get-contacts')
.then(({
data
}) => {
this.contacts = data.contacts;
for(let i=0; i<this.contacts.length; i++)
{
this.contact.push({'id': this.contacts[i]['id'], 'fullName' :
this.contacts[i]['fullName'], 'checked': true});
}
this.journal[0].players = this.contact;
this.pageLoader = false;
})
.catch(error => {
console.log(error);
});
},
Your addInput method creates and pushes new object into journal array, but each object created this way has a players property which references same array (this.contact)
The Difference Between Values and References in JavaScript
Easiest (but not most optimal) way to handle this is to create a copy of the array and objects inside for each new journal:
addInput() {
this.journal.push({
date: "",
timeStart: "",
timeEnd: "",
players: this.contact.map((player) => ({ ...player })),
description: ""
});
},

Vue.js remove item in arrray

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.

How to add text field dynamically with angular2

Hi guys I'm using angular2 in my project and I'm trying to add an input text dymanically, and it works heres the code :
TS:
initArray() {
return this._fb.group({
title: ['', Validators.required]
})
}
addArray() {
const control = <FormArray>this.myForm.controls['myArray'];
//this.myGroupName.push(newName);
control.push(this.initArray());
}
HTML:
<div formArrayName="myArray">
<div *ngFor="let myGroup of myForm.controls.myArray.controls; let i=index">
<div [formGroupName]="i">
<span *ngIf="myForm.controls.myArray.controls.length > 1" (click)="removeDataKey(i)" class="glyphicon glyphicon-remove pull-right" style="z-index:33;cursor: pointer">
</span>
<!--[formGroupName]="myGroupName[i]"-->
<div [formGroupName]="myGroupName[i]">
<div class="inner-addon left-addon ">
<i class="glyphicon marker" style="border: 5px solid #FED141"></i>
<input type="text" style="width:50% !important" formControlName="title" class="form-control" placeholder="Exemple : Maarif, Grand Casablanca" name="Location" Googleplace (setAddress)="getAddressOnChange($event,LocationCtrl)">
<br/>
</div>
</div>
<!--[formGroupName]="myGroupName[i]"-->
</div>
<!--[formGroupName]="i" -->
</div>
</div>
<br/>
<a (click)="addArray()" style="cursor: pointer">+ add text Field</a>
it gives me an error when i add a new text field, any suggestions please??
ERROR Error: Cannot find control with path: 'myArray -> 1 ->
Do not manupulate DOM with AngularJS
In controller create array of inputs
$scope.inputs = [];
$scope.inputs.push({ id: 'input1', value: 'input1' });
$scope.inputs.push({ id: 'input2', value: 'input2' });
$scope.inputs.push({ id: 'input2', value: 'input2' });
<input ng-repeat="input in inputs" ng-model="input.value">
Example

Vue-js removed selected date from textbox when add new element

Vue-js remove selected date from textbox when add new element. if i entered any text instead of date and add new element text is display as is it. but date is removed.
below is my HTML code
<div class="dateAvailabilityContainer">
<div class="dateAvailability" v-for="(date, index) in dates">
<div class="form-group date">
<input type="text" v-model='date.date' class="form-control date" v-bind:class="'datepicker_'+index" placeholder="Date">
</div>
<div class="form-group">
<input type="text" v-model='date.from' class="form-control from" placeholder="From">
</div>
<div class="form-group">
<input type="text" v-model='date.to' class="form-control to" placeholder="To">
</div>
<a href="#" v-if="index == 0" class="btn btn-success" v-on:click="addNewDate">
<i class="fa fa-plus"></i>
</a>
<a href="#" v-if="index > 0" class="btn btn-danger" v-on:click="removeThisDate(index)">
<i class="fa fa-minus"></i>
</a>
</div>
</div>
and below is my vue-js code
var addAvailability = new Vue({
el: '#addAvailability',
data: {
dates : [{
date : '',
from : '',
to : '',
}],
},
mounted: function () {
this.addDatePicker( this.dates.length - 1 );
},
methods: {
addNewDate: function () {
this.dates.push({
date: '',
from: '',
to: '',
});
this.addDatePicker( this.dates.length - 1 );
},
removeThisDate : function(index){
this.dates.splice(index, 1);
},
addDatePicker : function( id ){
setTimeout(function(){
console.log('.datepicker_'+id);
$('.datepicker_'+id).datepicker({
autoclose: true,
});
},500);
}
}
});
please help where i create a mistake.
please check in fiddle : https://jsfiddle.net/renishkhunt/bod4ob5y/19/
Thanks
Bootstrap (js) and jquery aren't friendly working with vue.
I think that it is because they modify DOM directly while vue also has a virtual DOM and works in a more data driven way.
Make them work together requires extra logic, I could only fix datetimepicker, I never haven't work with clockpicker before
First I change addNewDate function
//Save new date in a variable
var dateModel = {
date: '',
from: '',
to: '',
};
this.dates.push(dateModel);
var elementId = "datepicker_"+(this.dates.length - 1);
//pass new date to initDate function
this.initDate( elementId, dateModel );
In initDate we need to listen for date changes and update model
$('#'+id).datepicker({
...
}).on('changeDate', function(e){
dateModel.date = e.format();
});
Please see this partially working fiddle
As alternative you could use vue-flatpickr, at this moment is the best "vue's way" that I have found to handle date time inputs

Categories