Reutilizando el ejercicio del Curso básico de Vue y agregando las funcionalidades de este ejercicio:
Introducción
Bienvenidos al Curso Profesional de VueJS
Introducción a VueJS
CLI y Dev Tools
Herramientas y Experiencia de Desarrollo + Archivos .vue
CLI - Hello World
Webpack
Babel
Eslint
SASS y BULMA
PUG
Ejercicio de SASS y PUG
Ejercicio Avanzado de Pug y SASS
Manipulación del DOM
Expresiones
Directivas
Data Binding
Computed properties
Watchers
Eventos
Integración a Platzi Music
Ejercicio de Manipulación del DOM
REST y HTTP
Servicios
Consumir API's REST
Fetch API & Trae
Sistema de Componentes
Component
Creación de componentes
Reactividad
Ciclo de vida
Comunicación entre componentes padres e hijos
Comunicación de hijos hacia padres
Utilización de Slots
Comunicacion entre Componentes Genericos - Event Bus y Plugins
Vue Router
Introducción a Vue Router
Instalar vue-router y configurar router view
Crear y Navegar Rutas con router-link
Extendiendo VueJS
Modifiers
Filtros
Directivas Personalizadas
Mixins
Clases, Animaciones y Transiciones36
Vue Transitions y Animaciones de CSS
Vuex
Estado Centralizado, Flux y Vuex
State
Mutations
Getters
Actions
Integración a Platzi Music
Nuxt.js
Server Side Rendering
Nuxt.js
Conceptos Básicos de Nuxt
Deploy a Producción con Now
Qué es now
Configuración de now y deploy
Conclusiones
Cierre del curso
Bonus
Internacionalización con vue-i18n
Unit Test Karma - Mocha & Webpack
Implementación de Autenticación de Usuarios en Vue usando JWT
Hola, espero que hasta aquí estés disfrutando el curso, recuerda que para dominar un lenguaje o framework de programación debes practicar. Justamente por esto he creado este material para ti, puedes hacerlo en tu entorno local o puedes hacerlo en alguna herramienta como codepen.io. La idea es que practiques lo que has aprendido hasta este punto del curso, te invito a que revises el código de tus compañeros y que te animes a dar feedback así todos podrán ir creciendo.
Ejercicio:
Crear dentro de data una propiedad “name” de tipo String y una propiedad “tasks” de tipo de Array.
Agregar una expresión para mostrar el valor de name y utilizar la directiva apropiada para para mostrar en una lista cada uno de los elementos dentro de task. Cada “task” es un objeto con una propiedad “title” y otra “time”. Agreguemos las expresiones necesarias para que en cada tarea podamos visualizar ambas propiedades.
Agregar funcionalidad para crear una nueva tarea:
Vamos a necesitar una nueva propiedad llamada “newTask” que sea un Object. Dentro de este objeto también agregamos una propiedad “tilte” de tipo String y una propiedad “time” de tipo Number. Recuerda inicializar las propiedades con valores default.
Vamos a crear un método llamado “addTask” que agregue una nueva tarea al array “tasks”. Una vez agregada también va a reiniciar los valores dentro de “newTaks”. Ten en cuenta que antes de agregar la propiedad debemos chequear con los valores de “newTask.title” y “newTask.time” existan (sean distintos de “falsy”). Por otro lado es importante que cada elemento nuevo que agreguemos al array de “tasks” sea un objeto nuevo y no la instancia de “newTask”.
Vamos a agregar el HTML, para esto necesitamos dos “inputs” y un “button”. También debemos agregar las directivas correspondientes para enlazar el código con la vista.
Creamos también una funcionalidad para cancelar, para eso debemos crear un método llamado “cancel” que simplemente reinicie los valores de las propiedades de newTask. Recordemos agregar un button de HTML donde enlazar este nuevo método.
Es momento de saber cuantas horas llevamos trabajadas, para eso vamos a crear una computed property llamada “totalTime” donde se recorran todas las tareas y se calculo el total del tiempo trabajado. También vamos agregar un elemento HTML con la expresión necesaria para visualizar la propiedad.
Debemos integrar la app con el local storage del browser. Dentro del metodo “addTask”, guardamos toda la lista de tareas en dicho storage usando este metodo: “localStorage.setItem(‘tasks’, JSON.stringify(this.tasks))”.
Guardando las tareas en el browser podemos persistir la información aunque estemos cerrando o refrescando la página. Además, al momento de crearse el componente, debemos leer esta información para poder cargar la lista de tareas. Para eso dentro del hook “created”, escribimos el siguiente código: “this.tasks = JSON.parse(localStorage.getItem(‘tasks’)) || []”
Lo último que nos queda es poder eliminar las tareas que ya no queremos. Para eso vamos a crear un método que se llame “removeTask”. Este método debe recibir por parámetro el indice de la tarea y podemos utilizar ese indice (en conjunto con el método “splice” de Array) para eliminar el elemento. Recordemos que tendremos que agregar un botón por cada tarea y cada uno de estos se encarga de llamar al método “removeTask” enviando por parámetro el indice correspondiente. Recordemos invocar la funcionalidad que ya pusimos en “addTask”, para actualizar el local storage del Browser.
Por último vamos a mejorar la UI, cuando no haya tareas podemos mostrar un mensaje que indica que no hay ninguna tarea cargada y por otro lado ocultar el lista vacía.
Si en algún punto del ejercicio te sientes perdido, te dejo la versión que yo hice para que puedas consultarla en cualquier momento: https://codepen.io/ianaya89/pen/NgEeVO
Aportes 41
Preguntas 0
Reutilizando el ejercicio del Curso básico de Vue y agregando las funcionalidades de este ejercicio:
Reto Completado!!
Código: https://codepen.io/paolojoaquin/pen/OJpQZxo
Dejo mi código:
<template>
<div id="app">
<div class="tareas">
<input type="text" name="" id="taskTitle" placeholder="Tarea">
<input type="number" name="" id="taskTime" placeholder="Horas" min="1" step="1">
<button @click="addTask">Agregar tarea</button>
</div>
<section v-if="tasks.length > 0">
<div class="listaTareas">
<ul>
<li
v-for="task, index in tasks"
:key="index"
>
{{ task.title }} -> {{ task.time }} horas
<button
:key="index"
@click="deleteTask"
>
Borrar tarea {{ task.title }}
</button>
</li>
</ul>
</div>
<div class="tiempo">
<p>Tiempo total: {{ totalTime }} horas</p>
</div>
</section>
<section v-else>
<h1>No hay tareas por el momento</h1>
</section>
</div>
</template>
<script>
export default {
data() {
return {
tasks: [],
newTask: {
title: '',
time: 0
}
};
},
methods: {
addTask() {
const title = document.getElementById('taskTitle').value;
const time = parseInt(document.getElementById('taskTime').value);
if (title !== '' && time !== '') {
this.newTask.title = title;
this.newTask.time = time;
this.tasks.push(this.newTask);
this.newTask = {
title: '',
time: 0
};
} else {
alert('La tarea y el tiempo deben tener un valor');
}
localStorage.setItem('tasks', JSON.stringify(this.tasks));
},
deleteTask(task) {
const index = this.tasks.indexOf(task);
this.tasks.splice(index, 1);
localStorage.setItem('tasks', JSON.stringify(this.tasks));
}
},
computed: {
totalTime() {
let total = 0;
this.tasks.forEach(task => {
total += parseInt(task.time);
});
return total;
}
},
created() {
const tasks = localStorage.getItem('tasks');
if (tasks) {
this.tasks = JSON.parse(tasks) || [];
}
}
};
</script>
<style lang="scss">
</style>
Solución:
https://codepen.io/jesuskinto/pen/BejGpr
Este es mi prototipo 100% funcional ademas le añadí un plus con las actividades completada y una barra de progreso para saber como vamos.
HTML
<template lang="pug">
#app
.columns
.column
.column
h1 Tareas y horas
br
input.input.is-8(type="text" v-model="title" name="title" placeholder="title" )
input.input.is-8(type="text" v-model="time" name="time" placeholder="time" )
input.button.link(type="submit" name="submit" @click="addTask(title,time)")
p(v-if="totalTime!==0") {{totalTime}}
div(v-for="(task,i) in tasks")
ul
li {{task.title}} - {{task.time}}
button.delete.is-medium(@click="removeTask(i)")
br
.column
</template>
JS
<script>
export default {
name: 'app',
data () {
return {
title:'',
time:0,
tasks:[]
}
},
computed:{
totalTime () {
let total = 0
this.tasks.map(function(sum){
total += sum.time
})
return total
}
},
created(){
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
methods:{
addTask (title, time) {
if(title, time){
const newTask ={
title,
time : parseInt(time)
}
this.tasks.push(newTask);
}else(
alert('debe llenar todos los campos')
)
localStorage.setItem('tasks',JSON.stringify(this.tasks))
this.cancel ()
},
cancel () {
this.title = '',
this.time = ''
},
removeTask (i) {
let remove = this.tasks.splice(i,1);
localStorage.setItem('tasks',JSON.stringify(this.tasks))
return remove
}
}
}
</script>
Mi frontend no es muy bueno, pero aquí va, sigo usando bulma, no me gustó que no tiene clases como tan practicas en comparación de bootstrap para listas y hay que desarrollar mas del lado del css, pero bueno, la funcionalidad está.
<template lang="pug">
#app
section.section
nav.nav.has-shadow
.container
.field
label.label Título de la tarea
.control
input.input.is-large(type="text",
placeholder="Título de la tarea"
v-model="title")
.field
label.label Tiempo de trabajo
.control
input.input.is-large(type="text",
placeholder="Tiempo trabajado"
v-model="time")
.field.is-grouped.is-grouped-right
.control
a.button.is-info.is-large(@click="addTask") Agregar Tarea
a.button.is-danger.is-large(@click="deleteTask") × Eliminar Lista completa
br
br
h2 {{ timeWork }}
p
small {{ numberTask }}
.container
.ul
.li(v-for="(t, index) in tasks") {{ t.title }} - {{ t.time }}
a.button.is-danger(@click="deleteThisTask(index)") ×
p.error
small {{ mensajeError }}
</template>
<script>
const tasks = []
export default {
name: 'app',
created(){
this.tasks = JSON.parse(localStorage.getItem(tasks)) || []
},
data () {
return {
title: '',
time: '',
tasks: [],
mensajeError: '',
indexList: ''
}
},
computed:{
numberTask(){
return `Tareas Pendientes: ${this.tasks.length}`
},
timeWork(){
let horasTrabajadas = 0
for(let item of this.tasks){
horasTrabajadas += Number(item.time)
}
return `Hasta el momento hemos trabajado ${horasTrabajadas} hrs.`
}
},
methods:{
addTask(){
if(this.title === '' || this.time === ''){
this.mensajeError = 'Debe indicar los dos elementos título y horario'
}else{
if (!/^([0-9])*$/.test(this.time)){
this.mensajeError = 'El tiempo debe ser un número'
}else{
this.tasks.push({title: this.title, time: this.time})
this.title = ''
this.time = ''
this.mensajeError = ''
localStorage.setItem(tasks, JSON.stringify(this.tasks))
}
}
},
deleteTask(){
this.tasks = []
localStorage.setItem(tasks, JSON.stringify(this.tasks))
},
deleteThisTask(index){
this.tasks.splice(index, 1)
localStorage.setItem(tasks, JSON.stringify(this.tasks))
}
}
}
</script>
<style lang="scss">
@import './scss/main.scss';
.results {
margin-top: 15px;
}
.error {
color: red;
font-weight: bolder;
}
.button {
margin-right: 10px;
}
</style>
Originalmente lo hice con html porque no me gusta pug pero lo converti a pug para ustedes
.conteiner
nav.nav.justify-content-center.p-3.mb-2.bg-info.text-white
a.nav-link.text-dark(href='#') Home
.conteiner
| {{ name }}
.conteiner
.col-12
.d-flex.justify-content-center
.form-group
label(for='') Name
input.form-control(type='text' placeholder='Add Name' v-model='title')
small.form-text.text-muted Add the new Title Name
.d-flex.justify-content-center
.form-group
label(for='') Time
input.form-control(type='text' placeholder='Add time' v-model='time')
small.form-text.text-muted Add the new time Name
button.btn.btn-primary(type='button' v-on:click='addTask()' data-toggle='modal' data-target='#exampleModal')
| Add
button.btn.btn-danger(type='button' v-on:click='restartTask()' data-toggle='modal' data-target='#exampleModal')
| cancel
table.table
thead
tr
th Title
th Time
tbody
tr(v-for='(item, index) in task' :key='item')
td(scope='row') {{ item.title }}
td(scope='row') {{ item.time }}
td(scope='row')
button.btn.btn-danger(type='button' v-on:click='remove(index)' data-toggle='modal' data-target='#exampleModal')
| ×
p.text-success.totalTime {{ totalTime }}
#exampleModal.modal.fade(v-if='showMessage' tabindex='-1' role='dialog' aria-labelledby='exampleModalLabel' aria-hidden='true')
.modal-dialog(role='document')
.modal-content
.modal-header
h5.modal-title Modal title
button.close(type='button' data-dismiss='modal' aria-label='Close')
span(aria-hidden='true') ×
.modal-body
p {{ message }}```
Hola a todos, realicé el ejercicio con unas cuantas funciones extras de crud.
–>
Screenshot:
TaskManager.vue
/* eslint-disable vue/html-self-closing */
<template lang="pug">
#app
.container
.section.p-0
div.mb-6
<div :class="messageClass" v-if="message">
<button class="delete" aria-label="delete" @click="message=false"></button>
| {{messageText}}
</div>
p.title.is-large.is-info.mt-6.mb-0
| Task Manager
p.has-text-right
button.button.is-small.is-primary(@click="modalClass='modal is-active'; clear()")
| <i class="fa fa-plus" aria-hidden="true"></i> <strong> New task</strong>
button.button.is-small.is-danger.ml-4(@click="deleteSelected")
| <i class="fa fa-trash" aria-hidden="true"></i> <strong class="ml-2"> Delete selected tasks</strong>
table.table.is-bordered.is-hoverable.mt-2.is-fullwidth(v-show="tasks.length > 0")
thead
tr
th
input(type="checkbox" v-model="selectedAll")
th Name
th Description
th Time
th Ops.
tbody
tr(v-for="(task, index) in tasks")
td
input(type="checkbox" v-model="selected" :value="index")
td {{task.name}}
td {{task.description}}
td {{task.time}} hrs
td
a.button.is-danger.is-small.mr-2(@click="deleteTask(index)") <i class="fa fa-times" aria-hidden="true"></i>
a.button.is-info.is-small(@click="editTask(task, index)") <i class="fa fa-edit" aria-hidden="true"></i>
tfoot
tr
td.has-text-right(colspan="3")
strong Total Time
td.has-text-left(colspan="2")
| {{getTotalTime}} hrs
div(v-if="!tasks.length")
p.message.is-info.p-4.mt-4
strong No hay tareas aún
div
<div :class="modalClass">
<div class="modal-background"></div>
<div class="modal-content">
div.my-4
<div :class="messageClass" v-if="messageInDialog">
<button class="delete" aria-label="delete" @click="messageInDialog=false"></button>
| {{messageText}}
</div>
.card.p-5
.card-header.title.has-text-right
span(v-if="editTaskIndex == -1") Create a new task
span(v-else) Edit task
.card-content
.content
.field
input.input(type="text" v-model="aTask.name" placeholder="Task name")
.field
textarea.textarea(v-model="aTask.description" placeholder="Task Description")
.field.has-text-left
input.input(type="number" v-model="aTask.time" placeholder="Time" style="width:120px")
.field(v-if="editTaskIndex == -1")
a.button.is-primary.is-medium(@click="addTask") Save task
a.button.is-secondary.is-medium.ml-3(@click="modalClass='modal'") Close
.field(v-else)
a.button.is-primary.is-medium(@click="updateTask") Update task
</div>
<button class="modal-close is-large" @click="modalClass='modal'" aria-label="close"></button>
</div>
</template>
<script>
export default {
name: "Tasks",
data () {
return {
selected: [],
editTaskIndex: -1,
messageText: "The task was successfully saved.",
messageClass: "notification is-success",
message: false,
messageInDialog: false,
aTask: {
name: "",
time: 0,
description: ""
},
totalTime: 0,
modalClass: "modal",
tasks: []
};
},
computed: {
getTotalTime (key = "time") {
return this.tasks.reduce((a, b) => +a + +b.time, 0);
},
selectedAll: {
set (val) {
this.selected = [];
if (val) {
for (let i = 0; i < this.tasks.length; i++) {
this.selected.push(i);
}
}
},
get () {
return this.selected.length === this.tasks.length;
}
}
},
watch: {
},
created () {
this.tasks = JSON.parse(localStorage.getItem("tasks")) || [];
},
mounted () {
console.log("App Mounted");
},
methods: {
deleteSelected () {
const sel = this.selected.length;
if (sel <= 0) {
this.showMessage("notification is-warning", true, "You haven't selected any task to be deleted");
return;
}
if (sel > 0) {
for (let i = 0; i <= (sel); i++) {
// Delete selected items
this.tasks.splice(i, sel);
}
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.showMessage("notification is-info", true, sel + " task(s) deleted successfully");
this.selected = [];
}
},
updateTask () {
if (this.aTask.name.length > 0 && !isNaN(this.aTask.time)) {
this.tasks[this.editTaskIndex] = { name: this.aTask.name, time: this.aTask.time, description: this.aTask.description };
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.showMessage("notification is-success", true, "The task '" + this.tasks[this.editTaskIndex].name + "' was edited");
this.editTaskIndex = -1;
this.modalClass = "modal";
setTimeout(() => {
this.message = false;
}, 3000);
} else {
this.showMessage("notification is-danger", true, "Please review you information", true);
}
},
editTask (task, index) {
this.modalClass = "modal is-active";
this.aTask = task;
this.editTaskIndex = index;
},
showMessage (messageClass = "notification is-info", show = true, messageText, inDialog = false) {
this.messageText = messageText;
this.messageClass = messageClass;
if (inDialog) {
this.messageInDialog = true;
} else {
this.message = show;
}
setTimeout(() => {
!inDialog ? this.message = false : this.messageInDialog = false;
}, 3000);
},
deleteTask (index) {
const taskName = this.tasks[index].name;
this.tasks.splice(index, 1);
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.showMessage("notification is-info", true, `The task ${taskName} was deleted`);
},
clear () {
this.aTask.name = "";
this.aTask.time = 0;
this.aTask.description = "";
this.editTaskIndex = -1;
},
addTask () {
if (this.aTask.name.length > 0 && !isNaN(this.aTask.time)) {
if (this.aTask.time > 0) {
const newTask = { name: this.aTask.name, time: this.aTask.time, description: this.aTask.description };
this.tasks.push(newTask);
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.modalClass = "modal";
this.showMessage("notification is-success", true, "The task was successfully saved");
this.clear();
} else {
this.showMessage("notification is-danger", true, "Data for time must be a positive number", true);
}
} else {
this.showMessage("notification is-danger", true, "Please review you information", true);
// this.modalClass = "modal";
setTimeout(() => {
this.message = false;
}, 3000);
}
}
}
};
</script>
main.scss
@import '../../node_modules/bulma/bulma.sass';
<template lang="pug" >
#home
.container.mio
.columns
.column.is-6.is-offset-3.is-child.box
p.has-text-black.has-text-weight-bold.pb-4 Lista de Actividades
.field.is-horizontal
.field-label.is-normal
label.labelmio Nombre Actividad:
.field-body
.field
.control
input.input(placeholder="task", v-model="newTask.title")
.field.is-horizontal
.field-label.is-normal
label.labelmio Tiempo ejecucion:
.field-body
.field
.control
input.input(placeholder="time", v-model="newTask.time", type="number")
button.button.buttonmio(@click="addTasks") Agregar
button.button.buttonmio(@click="cancel") Cancelar
.columns
.column.is-8.is-offset-2.box.mio
p(v-show="!tasks.length") Aun no hay tareas cargadas
p(v-show="tasks.length").has-text-black.has-text-weight-bold Actividades realizadas
p(v-for="t in tasks") Actividad: {{ t.title }} Tiempo de ejecucion: {{ t.time }}
button.button.buttonmio2.is-danger.is-outlined(@click="removeTask(t)")
span.icon.is-small
i.fas.fa-times
p Total tiempo {{ totalTime }}
</template>
<script>
export default {
name: 'Home',
data () {
return {
name: '',
tasks: [],
newTask: {
title: '',
time: 0
}
}
},
methods: {
cancel () {
this.newTask.title = this.newTask.time = ''
},
addTasks () {
var copi = Object.assign({}, this.newTask)
this.tasks.push(copi)
this.cancel()
localStorage.setItem('tasks', JSON.stringify(this.tasks))
},
removeTask (task) {
var i = this.tasks.indexOf(task)
console.log(i)
if (i !== -1) {
this.tasks.splice(i, 1)
}
localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
},
computed: {
totalTime () {
var suma = 0
for (var t = 0; t < this.tasks.length; t++) {
const element = this.tasks[t].time
suma = suma + parseInt(element)
}
return suma
}
},
created () {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
components: {}
}
</script>
<style scoped>
.mio{
background: white;
margin-top: 50px;
}
.labelmio{
margin-left: -70px;
margin-right: 30px;
}
.buttonmio{
margin-top: 20px;
}
.buttonmio2{
margin-left: 90px;
padding: 20px;
width: 15px;
}
</style>```
Done! :3
<template>
<h1>Nombre: {{ name }}</h1>
<input type="text" v-model="newTask.title" placeholder="Nombre de la tarea">
<input type="text" v-model="newTask.time" placeholder="Tiempo de la tarea">
<button @click="addTask">Añadir tarea</button>
<div v-show="tasks.length > 0">
<ul>
<li v-for="(task, i) in tasks" :key="i">
<b>Nombre de la tarea:</b> {{ task.title }}
<b>Tiempo:</b> {{ task.time }}
<button class="is-danger" @click="removeTask(i)">×</button>
</li>
</ul>
<p>Se han trabajado {{ totalTime }} horas</p>
</div>
<p v-show="tasks.length <= 0">No hay tareas para mostrar</p>
</template>
<script>
export default {
name: 'App',
components: {},
created() {
this.tasks = JSON.parse(localStorage.getItem("tasks")) || [];
},
data() {
return {
name: "",
tasks: [],
newTask: {
title: "",
time: ""
}
}
},
methods: {
saveInLocalSotrage() {
localStorage.setItem("tasks", JSON.stringify(this.tasks));
},
addTask() {
const task = this.newTask;
if (task.title != "" && task.time != "") {
this.tasks.push({
title: task.title,
time: task.time
});
task.title = "";
task.time = "";
this.saveInLocalSotrage();
}
},
removeTask(index){
this.tasks.splice(index, 1);
this.saveInLocalSotrage();
}
},
computed: {
totalTime() {
let hours = 0;
const tasks = this.tasks;
for (const task of tasks)
hours += parseInt(task.time);
return hours;
}
}
}
</script>
<style lang="scss">
/* Es una buena pŕactica importar los estiulos generales desde el componente App.vue */
@import "./scss/main.scss";
</style>
Les presento mi práctica:
<template lang="pug">
.container.is-fluid
section.section
center
img(src="../../assets/images/logo_azael.png", width="150")
h1.is-size-2.tasks-title.has-text-centered.is-paddingless Administrador de Tareas
br
.columns
.column.is-6.is-offset-one-quarter
.card
header.card-header
h1.card-header-title
| Crear Tarea Nueva
.card-content
.content
.notification.is-warning(v-show="warning")
|Debe completar los campos correctamente
button.delete(@click="warning = false")
.field
label.label Tarea:
p.control.has-icons-left
input.input(
type='text',
placeholder='Nombre de tu tarea',
v-model="newTask.task")
span.icon.is-small.is-left
i.fa.fa-clipboard-check
.field
label.label Horas:
p.control.has-icons-left
input.input(
type='number',
placeholder='Tiempo invertido',
v-model="newTask.time")
span.icon.is-small.is-left
i.fa.fa-stopwatch
button.button.is-primary.addTask(@click="addTask") Agregar
button.button(@click="cancel") Cancelar
.columns
.column.is-6.is-offset-one-quarter
.card
header.card-header
h1.card-header-title
| Listado de Tareas
.card-content
.content.table_wrapper
table.table.has-text-centered
thead
tr
th Nombre tarea
th Tiempo Invertido
th Eliminar
tbody
tr(v-show="alert")
td.has-text-centered(colspan="3", v-if="!tasks.length")
| No se encontraron tareas registradas
tr(v-for="t in tasks")
td {{ t.task }}
td {{ t.time }}
td
button.button.is-danger(@click="deleteTask(t)")
i.fa.fa-times
footer.card-footer
p.card-footer-item
span
strong {{ `Total de Horas: ${totalTime} ` }}
</template>
<script>
export default {
name: "tasks",
data () {
return {
alert: true,
warning: false,
newTask: { task : '', time : 0 },
tasks: [],
sumaHoras: 0
}
},
methods:{
addTask () {
const self = this;
if (self.newTask.task == '' || self.newTask.time == 0 ) {
self.warning = true
return false
} else {
self.warning = false
}
if (self.tasks.length > 0) {
self.alert = false
}else{
self.alert = true
}
self.tasks.push(self.newTask);
this.cancel();
},
cancel () {
const self = this;
self.newTask = {task : '', time : 0}
},
deleteTask (task) {
const self = this;
let index = self.tasks.indexOf(task);
self.tasks.splice(index, 1)
}
},
computed:{
totalTime () {
const self = this;
let suma = 0;
self.tasks.forEach(task => {
suma = parseInt(suma) + parseInt(task.time)
});
return suma;
}
}
}
</script>
<style scoped>
.table_wrapper{
overflow-x: auto;
}
.addTask{
margin:0 10px;
}
</style>
Comparto mi ejercicio, me costó trabajo por que lo hice sin bootstrap
https://codepen.io/carlos-fuentes-the-selector/pen/WWQxYK
Aquí mi código
<template lang="pug">
#container
h2 {{ name }}
.columns
.column.is-4
.field
label.label.labelLeft(for="name") Nombre
input.input.is-small(type="text" v-model:name="newTask.name" id="name")
.field
label.label.labelLeft(for="time") Tiempo
input.input.is-small(type="text" v-model:name="newTask.time" id="time")
.buttonLayout
button.button.is-success.buttonLeft(@click="addTask") Crear tarea
button.button.is-info.buttonLeft(@click="cancel") Cancelar
.column.is-8
div.table
table(v-show="tasks.length")
tr
td Nombre
td Titulo
td
tr(v-for="(task, index) in tasks")
td {{task.name}}
td {{ task.time }}
td
button.button.is-danger(@click="removeTask(index)" ) X
h2(v-show="!tasks.length") no hay ninguna tarea cargada
p.message.is-danger.message-body.center(v-show="tasks.length") Tiempo total de trabajo {{ totalTime }}
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
name: 'Servicio de tareas',
tasks: [],
newTask: {
name: '',
time: 0
}
}
},
created () {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
methods: {
addTask () {
if (this.newTask.name === '' || this.newTask.time === 0) {
return
}
let name = this.newTask.name
let time = this.newTask.time
this.tasks.push({
name,
time
})
localStorage.setItem('tasks', JSON.stringify(this.tasks))
},
cancel () {
this.newTask.name = ''
this.newTask.time = 0
},
removeTask (index) {
this.tasks.splice(index, 1)
localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
},
computed: {
totalTime () {
let timeTotal = 0
for (let i in this.tasks) {
timeTotal += parseInt(this.tasks[i].time)
}
return timeTotal
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" scoped>
@import '~bulma/bulma.sass';
table {
width: 100%;
margin-left: 5%;
margin-right: 5%;
}
.inputLayout {
display: inline;
}
h2 {
margin-top: 5%;
margin-bottom: 5%;
}
.labelLeft{
text-align: left;
}
.buttonLeft{
margin-left: 5%;
}
.center {
text-align: center;
}
</style>
<template>
<div id="app">
<section class="section">
<nav class="nav has-shadow">
<div class="container">
<div class="field has-addons">
<div class="control is-expanded">
<input
v-model="newTask.title"
type="text"
placeholder="Titulo"
class="input is-large">
</div>
<div class="control is-expanded">
<input
v-model="newTask.time"
type="number"
placeholder="Tiempo"
class="input is-large">
</div>
<div class="control">
<a class="button is-info is-large" @click="addTask">Add Task</a>
</div>
<div class="control">
<a class="button is-danger is-large" @click="cancel">×</a>
</div>
</div>
<p><small>{{ totalTime }}</small></p>
</div>
<div class="container">
<p>{{ name }}</p>
</div>
<div class="container results">
<div class="columns" >
<template v-if="tasks.length != 0">
<div class="column" v-for="(t, i) in tasks">
<p>{{ t.title }} - {{ t.time }}</p>
<br>
<a class="button is-danger is-large" @click="removeTask(i)">×</a>
</div>
</template>
<template v-else>
<p>No hay tasks</p>
</template>
</div>
</div>
</nav>
</section>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
name: '',
tasks: [],
newTask: {
tilte: '',
time: 0
}
}
},
created: function () {
this.tasks = JSON.parse(window.localStorage.getItem('tasks')) || []
},
computed: {
totalTime () {
var total = 0
for (var i = 0; i < this.tasks.length; i++) {
total = parseInt(total) + parseInt(this.tasks[i].time)
}
return `Tiempo total: ${total}`
}
},
methods: {
removeTask (i) {
this.tasks.splice(i)
window.localStorage.setItem('tasks', JSON.stringify(this.tasks))
},
cancel () {
this.newTask = {
tilte: '',
time: 0
}
},
addTask () {
if (this.newTask.title && this.newTask.time) {
this.tasks.push({
title: this.newTask.title,
time: this.newTask.time
})
}
this.newTask = {
tilte: '',
time: 0
}
window.localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
}
}
</script>
<style lang="scss">
@import './assets/scss/main.scss';
.results{
margin-top: 50px;
}
</style>
Adjunto mi aporte
<template lang ="pug">
#app
section.section
nav.nav.has-shadow
.container
h1.title.is-1.has-text-centered Gestor de Tareas
.container(v-show="!name")
.field.is-3.has-addons
.control
.columns
.column
input#name.input.is-large(type="text", placeholder="Ingresa tu nombre", v-model="newName")
.control
.columns
.column
a.button.is-primary.is-large(type="submit", @click="addName") Ok
h2.title.is-4(v-show="name") Tareas de {{ name }}
hr
.columns(v-show="name")
.column
h2.title.is-3.has-text-centered Agregar Tarea
.columns.is-mobile
.column.is-three-quarters
.field
.control
input.input(type="text", v-model="task.title", placeholder="Titulo de Tarea")
.column
.field
.control
input.input.is-primary(type="number", placeholder="0", v-model="task.time")
hr
a.button.is-primary(@click="addTask") +
a.button.is-danger(@click="cancel") x
.column
h2.title.is-3.has-text-centered Lista de Tareas
p.has-text-centered(v-show="!tasks.length") Aun no hay tareas cargadas
div(v-show="tasks.length")
ol
li.has-text-centered(v-for="t in tasks")
.columns
.column
.tags.has-addons
p.tag.is-medium.is-info {{ t.title }}
span.tag.is-medium.is-warning {{ t.time }}
.column
button.button.tag.is-danger(@click="removeTask") eliminar
.column
h2.title.is-3.has-text-centered Tiempo Requerido
.tags.has-addons.has-text-centered
span.tag.is-medium.is-warning {{ totalTime }}
span.tag.is-medium.is-medium Horas
</section>
</template>
<script>
export default {
name: 'app',
data () {
return {
newName: null,
name: '',
tasks: [],
task: {
title: '',
time: 0
}
}
},
created () {
this.tasks = JSON.parse(window.localStorage.getItem('tasks')) || []
this.name = JSON.parse(window.localStorage.getItem('name'))
},
computed: {
totalTime () {
if (!this.tasks.length) {
return 0
}
let total = 0
this.tasks.forEach(t => {
total += parseInt(t.time)
})
return total
}
},
watch: {
},
methods: {
addName () {
this.name = this.newName
window.localStorage.setItem('name', JSON.stringify(this.name))
},
addTask () {
if (!this.task.title || !this.task.time) {
return
}
this.tasks.push({
title: this.task.title,
time: this.task.time
})
this.task.title = ''
this.task.time = 0
window.localStorage.setItem('tasks', JSON.stringify(this.tasks))
},
cancel () {
this.task.title = ''
this.task.time = 0
},
removeTask (index) {
this.tasks.splice(index, 1)
window.localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
}
}
</script>
<style lang="scss">
@import './scss/main.scss';
html {
padding: 20px;
color: #3d3d3d;
}
</style>
Les dejo mi ejercicio: https://codepen.io/ludwingperezt/pen/gEWPGx
No agregué estilos porque quería enfocarme en la solución del código con vue. Ahora que veo lo que hicieron ustedes me da vergüenza como dejé el ejercicio, probablemente lo haga luego jejeje
<template>
<div id="app">
<div class="container is-fluid">
<nav class="level">
<div class="level-left">
<div class="level-item">
<div class="field">
<div class="control">
<input class="input is-info" type="text" placeholder="Titulo de la tarea" v-model="newTasks.value">
</div>
</div>
</div>
<div class="level-item">
<div class="field">
<div class="control">
<input class="input is-primary" type="number" placeholder="Tiempo de la tarea" v-model="newTasks.time">
</div>
</div>
</div>
<div class="level-item">
<a class="has-text-centered button is-link is-outlined is-medium" v-on:click="addTask(newTasks)">Añadir Tarea</a>
</div>
<div class="level-item">
<a class="has-text-centered button is-primary is-outlined is-medium" v-on:click="cancelar">Cancelar</a>
</div>
<div class="level-item" v-show="!mostrar">
<article class="message is-danger">
<div class="message-body">
Error el titulo no debe de estar vacio y el tiempo de la tarea debe de ser mayor a "0".
</div>
</article>
</div>
</div>
<div class="level-right">
<div class="level-item">
<p class="has-text-centered">
<a class="link is-info">{{name}}</a>
</p>
</div>
</div>
</nav>
<div v-show="tasks != ''">
<article class="media" v-for="task in tasks" :key="task">
<figure class="media-left">
<div class="page__toggle">
<label class="toggle">
<input class="toggle__input" type="checkbox" v-if="task.check" checked="checked">
<input class="toggle__input" type="checkbox" v-else>
<span class="toggle__label">
<span class="toggle__text"></span>
</span>
</label>
</div>
</figure>
<div class="media-content">
<div class="content">
<div class="columns is-multiline is-variable is-1">
<div class="column is-two-thirds">
<p class="notification is-info">{{task.value}}</p>
</div>
<div class="column">
<p class="notification is-primary">{{task.time}}</p>
</div>
</div>
</div>
</div>
<div class="media-right">
<button class="delete" v-on:click="removeTask(task)"></button>
</div>
</article>
<div class="media columns is-multiline is-variable is-1">
<div class="column is-full">
<p class="notification is-link">{{totalTimeResult}}</p>
</div>
</div>
</div>
<article class="media" v-show="tasks == ''">
<div class="column is-full">
<p class="notification is-warning">No existe ninguna tarea</p>
</div>
</article>
</div>
</div>
</template>
<script>
const tracks = [
{ id: 1, name: 'Muchacha', artist: 'Luis Alberto Spinetta' },
{ id: 2, name: 'Hoy aca en el baile', artist: 'El Pepo' },
{ id: 3, name: 'I was made for loving you', artist: 'Kiss' }
]
export default {
name: 'app',
data () {
return {
name: 'Angel Infanti',
rayas: 16,
mostrar: true,
tasks: [],
newTasks: {
value: '',
time: 0,
check: true
}
}
},
created () {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
computed: {
searchMessage () {
return `Encontrados: ${this.tracks.length}`
},
totalTimeResult () {
var totalTime = 0
for (var recorrido = 0; recorrido < this.tasks.length; recorrido++) {
console.log(this.tasks[recorrido].time)
totalTime = totalTime + this.tasks[recorrido].time
}
return `Tiempo total de ectividades: ${totalTime}`
}
},
methods: {
addTask (newTasks) {
newTasks.time = parseInt(newTasks.time)
if (newTasks.value !== '' && newTasks.time > 0) {
this.tasks.push(newTasks)
this.newTasks = {
value: '',
time: 0,
check: true
}
this.mostrar = true
localStorage.setItem('tasks', JSON.stringify(this.tasks))
} else {
this.mostrar = false
}
},
removeTask (indice) {
this.tasks.splice(indice, 1)
localStorage.setItem('tasks', JSON.stringify(this.tasks))
},
cancelar () {
this.newTasks = {
value: '',
time: 0,
check: false
}
},
search () {
this.tracks = tracks
}
}
}
</script>
<style lang="scss">@import './scss/main.scss'</style>
<style type="scss">
.toggle{
--uiToggleSize: var(--toggleSize, 20px);
--uiToggleIndent: var(--toggleIndent, .4em);
--uiToggleBorderWidth: var(--toggleBorderWidth, 2px);
--uiToggleColor: var(--toggleColor, #000);
--uiToggleDisabledColor: var(--toggleDisabledColor, #868e96);
--uiToggleBgColor: var(--toggleBgColor, #fff);
--uiToggleArrowWidth: var(--toggleArrowWidth, 2px);
--uiToggleArrowColor: var(--toggleArrowColor, #fff);
display: inline-block;
position: relative;
}
.toggle__input{
position: absolute;
left: -99999px;
}
.toggle__label{
display: inline-flex;
cursor: pointer;
min-height: var(--uiToggleSize);
padding-left: calc(var(--uiToggleSize) + var(--uiToggleIndent));
}
.toggle__label:before, .toggle__label:after{
content: "";
box-sizing: border-box;
width: 1em;
height: 1em;
font-size: var(--uiToggleSize);
position: absolute;
left: 0;
top: 0;
}
.toggle__label:before{
border: var(--uiToggleBorderWidth) solid var(--uiToggleColor);
z-index: 2;
}
.toggle__input:disabled ~ .toggle__label:before{
border-color: var(--uiToggleDisabledColor);
}
.toggle__input:focus ~ .toggle__label:before{
box-shadow: 0 0 0 2px var(--uiToggleBgColor), 0 0 0px 4px var(--uiToggleColor);
}
.toggle__input:not(:disabled):checked:focus ~ .toggle__label:after{
box-shadow: 0 0 0 2px var(--uiToggleBgColor), 0 0 0px 4px var(--uiToggleColor);
}
.toggle__input:not(:disabled) ~ .toggle__label:after{
background-color: var(--uiToggleColor);
opacity: 0;
}
.toggle__input:not(:disabled):checked ~ .toggle__label:after{
opacity: 1;
}
.toggle__text{
margin-top: auto;
margin-bottom: auto;
}
/*
The arrow size and position depends from sizes of square because I needed an arrow correct positioning from the top left corner of the element toggle
*/
.toggle__text:before{
content: "";
box-sizing: border-box;
width: 0;
height: 0;
font-size: var(--uiToggleSize);
border-left-width: 0;
border-bottom-width: 0;
border-left-style: solid;
border-bottom-style: solid;
border-color: var(--uiToggleArrowColor);
position: absolute;
top: .5428em;
left: .2em;
z-index: 3;
transform-origin: left top;
transform: rotate(-40deg) skew(10deg);
}
.toggle__input:not(:disabled):checked ~ .toggle__label .toggle__text:before{
width: .5em;
height: .25em;
border-left-width: var(--uiToggleArrowWidth);
border-bottom-width: var(--uiToggleArrowWidth);
will-change: width, height;
transition: width .1s ease-out .2s, height .2s ease-out;
}
/*
=====
LEVEL 2. PRESENTATION STYLES
=====
*/
/*
The demo skin
*/
.toggle__label:before, .toggle__label:after{
border-radius: 2px;
}
/*
The animation of switching states
*/
.toggle__input:not(:disabled) ~ .toggle__label:before,
.toggle__input:not(:disabled) ~ .toggle__label:after{
opacity: 1;
transform-origin: center center;
will-change: transform;
transition: transform .2s ease-out;
}
.toggle__input:not(:disabled) ~ .toggle__label:before{
transform: rotateY(0deg);
transition-delay: .2s;
}
.toggle__input:not(:disabled) ~ .toggle__label:after{
transform: rotateY(90deg);
}
.toggle__input:not(:disabled):checked ~ .toggle__label:before{
transform: rotateY(-90deg);
transition-delay: 0s;
}
.toggle__input:not(:disabled):checked ~ .toggle__label:after{
transform: rotateY(0deg);
transition-delay: .2s;
}
.toggle__text:before{
opacity: 0;
}
.toggle__input:not(:disabled):checked ~ .toggle__label .toggle__text:before{
opacity: 1;
transition: opacity .1s ease-out .3s, width .1s ease-out .5s, height .2s ease-out .3s;
}
/*
=====
LEVEL 3. SETTINGS
=====
*/
.toggle{
--toggleColor: #690e90;
--toggleBgColor: #9b59b6;
--toggleSize: 50px;
}
</style>
Sigo construyendo mis interfaces de usuario con Vuetify. Este es el resultado final:
A continuación presento el código:
<template lang="pug">
v-app
v-content
v-container(fluid)
v-layout(align-center justify-center)
v-flex(xs12 sm8 md6 lg5)
v-card.elevation-12
v-toolbar(color="secondary" dark card prominent)
v-toolbar-title.headline.text-uppercase
span.font-weight-light {{ name }}
v-card-text
form(@submit.prevent="addTask")
v-container.pa-0(fluid)
v-layout(grid-list-xs wrap)
v-flex.px-1(xs12 sm8 md9 lg10)
v-text-field(v-model="newTask.title" label="Título")
v-flex.px-1(xs12 sm4 md3 lg2)
v-text-field(v-model="newTask.time" label="Tiempo (min.)" type="number" min="1")
v-flex.px-1(xs6)
v-btn(type="submit" color="primary" block) Add Task
v-flex.px-1(xs6)
v-btn(@click="cancel" block) Cancel
v-divider
v-list(two-line)
v-subheader Tareas
span.ml-1.font-weight-light (Tiempo total: {{ totalTime }} hrs.)
template(v-if="tasks.length > 0")
v-list-tile(v-for="(task, idx) in tasks" :key="idx" @click="")
v-list-tile-content
v-list-tile-title {{ task.title }}
v-list-tile-sub-title Tiempo: {{ task.time }} min.
v-list-tile-action
v-btn(@click="removeTask(idx)" color="error" flat fab)
v-icon delete
v-list-tile(v-else)
v-list-tile-content
v-list-tile-title.text-xs-center No tasks
v-snackbar(v-model="msg.show" :color="msg.color" :timeout="3000" bottom multi-line dark) {{ msg.text }}
</template>
<script>
export default {
name: 'App',
created () {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
data () {
return {
msg: {
show: false,
text: '',
color: ''
},
name: 'Leonardo Campo R.',
tasks: [
],
newTask: {
title: '',
time: 0
}
}
},
methods: {
addTask () {
if (!this.newTask.title || !this.newTask.time) {
this.showMsg('error', 'Debe ingresar un título y el tiempo')
return
}
this.tasks.push({ title: this.newTask.title, time: parseInt(this.newTask.time) })
this.save()
this.cancel()
},
removeTask (idx) {
this.tasks.splice(idx, 1)
this.save()
},
cancel () {
this.newTask.title = ''
this.newTask.time = 0
},
save () {
localStorage.setItem('tasks', JSON.stringify(this.tasks))
},
showMsg (color, text) {
this.msg.text = text
this.msg.color = color
this.msg.show = true
}
},
computed: {
totalTime () {
let time = 0
this.tasks.forEach((task) => {
time += task.time
})
return parseFloat((time / 60.0).toFixed(2))
}
}
}
</script>
Ejercicio:
<template lang="pug">
#app
.columns
.column {{ name }}
h1.title.has-background-info(v-if="!comprobarLista") las horas que debes invertir para ser un poco menos ignorante son: {{ totalTime }}
h1.title.has-background-warning(v-else) No hay tareas que mostrar
.column
h1 Agrega una nueva Tarea
input.input(v-model="newTask.title")
span(v-show="mensajeTitle").tag.is-warning.is-large El texto no es valido
input.input(v-model="newTask.time")
span(v-show="mensajeTime").tag.is-warning.is-large ingresa un número valido
br
br
button.button(@click="addTask") Agregar tarea
button.button.is-danger(@click="cancelTask") cancelar Tarea
.columns
.column
h1 Tus Tareas Pendientes son
ul
li(v-for="(task, index) in tasks")
span.tag.is-success {{index}} {{ task.title }}, Tiempo Estimado {{ task.time }} horas
button.delete(@click="deleteTask($event, index)")
</template>
<script>
export default {
name: 'app',
created () {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
data () {
return {
name: 'HERMESTO',
tasks: [
{
title: 'titulo 1',
time: 2
},
{
title: 'titulo 2',
time: 5
}
],
newTask: {
title: '',
time: 0
},
mensajeTitle: false,
mensajeTime: false
}
},
computed: {
totalTime () {
let total = 0
for (let i = 0; i < this.tasks.length; i++) {
total += parseInt(this.tasks[i].time)
}
return total
},
comprobarLista () {
if (this.tasks.length === 0) {
return true
} else {
return false
}
}
},
methods: {
addTask () {
if (this.newTask.title.trim().length === 0) {
this.mensajeTitle = true
return false
} else {
this.mensajeTitle = false
}
if (parseInt(this.newTask.time) > 0) {
this.mensajeTime = false
} else {
this.mensajeTime = true
console.log('falio')
return false
}
let tmpTask = {
title: '',
time: 0
}
tmpTask.title = this.newTask.title
tmpTask.time = this.newTask.time
this.newTask.title = ''
this.newTask.time = 0
this.tasks.push(tmpTask)
localStorage.setItem('tasks', JSON.stringify(this.tasks))
},
cancelTask () {
this.newTask.title = ''
this.newTask.time = 0
},
deleteTask ($event, index) {
this.tasks.splice(index, 1)
}
}
}
</script>
<style lang="scss">
@import './scss/main.scss';
.results {
margin-top: 50px
}
</style>
Dejo el mío. Me falta implementar algunas cosas pero funciona
https://codepen.io/hiteple/pen/XweZvO
Hecho con bulma en codepen!
Ejercicio completado
mi ejercicio
https://github.com/jonathandana/vue-platzi-tasks
Adjunto mi ejercicio
<template lang="pug">
#app
.panel.is-primary
.panel-heading Ejercicio de Manipulación del DOM by {{ name}}
.panel-block
.columns
.column
.box
.field
p.is-size-3 New Task
.field
label.control Title:
input.control(type="text", placeholder="Title", v-model="title")
.field
label.control Time
input.control(type="numeric", placeholder="Time", v-model="time")
.field
button.button.is-info(@click="addTask") Add Task
button.button.is-danger(@click="resetValues") Cancel
.column
.fieldset(v-if="tasks.length>0")
p.is-size-5(v-show="totalTime") Horas trabajadas: {{ totalTime }}
.columns
.column(v-for="(t, key) in tasks")
.box
p.is-size-7.has-text-weight-bold {{ t.title }}
p.is-size-7 {{ t.time}}
button.button.is-small(@click="removeTask(key)") Delete
.fieldset(v-else)
h1 No tasks yet!
</template>
<script>
export default {
name: 'app',
data () {
return {
name: 'ANDRES RUIZ',
tasks: [],
newTask: {},
title: '',
time: 0,
existsTasks: false
}
},
computed: {
totalTime () {
var time = 0
for (let index = 0; index < this.tasks.length; index++) {
time += parseInt(this.tasks[index].time)
}
return time
}
},
created () {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
methods: {
addTask () {
if ((this.title !== '') && (this.time > 0)) {
this.tasks.push({
title: this.title,
time: this.time
})
alert('Added correctly!')
this.resetValues()
localStorage.setItem('tasks', JSON.stringify(this.tasks))
} else {
alert('Check your values!')
}
},
resetValues () {
this.title = ''
this.time = 0
this.newTask = {}
},
removeTask (key) {
this.tasks.splice(key, 1)
alert('Deleted correctly!')
localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
}
}
</script>
<style lang="scss">
@import './scss/main.scss'
</style>
Aporto mi ejercicio, trate de hacer algo diferente pero implementando todos los puntos requeridos:
https://github.com/menkar91/note
Mi Trabajo
JS
export default {
name: "AddList",
data() {
return {
name: "",
task: [],
newTask: {},
time: 0,
title: "",
showMessage: false,
message: ""
};
},
methods: {
addTask() {
if (this.title != "" && this.time > 0) {
this.task.push({ time: this.time, title: this.title });
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.showMessage = true;
this.message = "Time was add";
} else {
this.showMessage = true;
this.message = "Time wasn't added";
}
},
restartTask() {
this.title = "";
this.time = 0;
this.rewTask = {};
this.showMessage = true;
this.message = "The time is restart";
},
remove(index) {
this.task.splice(index, 1);
this.showMessage = true;
this.message = "The time was deleted";
}
},
computed: {
totalTime() {
let sumTime = 0;
for (const key in this.task) {
sumTime += parseInt(this.task[key].time);
}
return sumTime;
}
},
created() {
this.tasks = JSON.parse(localStorage.getItem("tasks")) || [];
}
};
Javascript
var app = new Vue({
el: '#app',
data: {
name: 'Lucas Moreno',
tasks: [],
newTask: {title:'', time: null},
showMessage: false
},
methods: {
removeTask(index){
this.tasks.splice(index, 1);
localStorage.setItem("tasks", JSON.stringify(this.tasks));
},
addTask(){
if(this.newTask.title != '' && this.newTask.time != null){
this.tasks.push({title: this.newTask.title, time: this.newTask.time});
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.newTask.title = '';
this.newTask.time = null;
this.showMessage = false;
}
else{
this.showMessage = true;
}
},
cancel(){
this.newTask.title = '';
this.newTask.time = null;
}
},
computed:{
totalTime(){
let suma = 0;
for(let i = 0; i < this.tasks.length; ++i){
suma += parseInt(this.tasks[i].time);
}
return suma;
}
},
created(){
this.tasks = JSON.parse(localStorage.getItem("tasks")) || [];
}
})
pug
#app
h1 Organizador de tareas :D
p Nombre: {{ name }}
section
input(type="text" v-model="newTask.title" placeholder="Titulo de la tarea")
input(type="number" v-model="newTask.time" placeholder="Tiempo de la tarea")
button(@click="addTask") Agregar Tarea
button(@click="cancel") Cancelar Tarea
span(v-if="showMessage") Porfavor, no deje ningun espacio vacio
h2 Tareas por hacer:
ul
li(v-for="(task, index) in tasks")
div
span Titulo: {{task.title}} <br>
span Hora: {{task.time}}
button(@click="removeTask(index)") Tarea realizada
h2 Horas a trabajar: {{ totalTime }}
Hice el ejercicio en codepen, este es el link: https://codepen.io/hectortllo/pen/eYpYxQb?editors=1010
<template lang="pug">
#pxMoveDom
h1 {{ name }}
section.section
p Ingresa el nombre de la Tarea
input.input.is-medium( type="text"
placeholder="Título"
v-model="newTask.title")
p Ingresa el tiempo para realizarla
input.input.is-medium( type="number"
placeholder="Tiempo"
v-model="newTask.time")
a.button.is-info.is-large(@click='addTask') Agregar
a.button.is-danger.is-large(@click='cancel') ×
div(v-show="tasks.length")
ul
li(v-for="(t,i) in tasks") {{ t.title }} - {{ t.time }}
a.button.is-danger(@click='removeTask(i)') ×
h1 Tiempo total trabjado: {{ totalTime }}
div(v-show="!tasks.length")
p No hay elementos en la lista
</template>
<script>
export default {
name: 'pxMoveDOM',
data() {
return {
name: 'Lalo Rivero',
tasks: [],
newTask: { title: '', time: null }
}
},
methods: {
addTask() {
if (this.newTask.title != '' && this.newTask.time != null) {
let newObj = JSON.parse(JSON.stringify(this.newTask))
this.tasks.push(newObj)
localStorage.setItem('tasks', JSON.stringify(this.tasks))
this.newTask.title = ''
this.newTask.time = null
}
console.log(this.tasks)
},
cancel() {
this.newTask.title = ''
this.newTask.time = null
},
removeTask(index) {
this.tasks.splice(index, 1)
localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
},
computed: {
totalTime() {
let time = null
this.tasks.map(sum => {
time += parseInt(sum.time)
})
return time
}
},
created() {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
}
}
</script>
Aquí la solución:
https://codepen.io/ftalero/pen/mdeaOOM?editors=1010
✌
Ejercicio realizado:
<template lang="pug">
#app
.container
.control
input.input(
type="text"
placeholder="Titulo",
v-model="newTask.title"
)
.control
input.input(
type="text"
placeholder="Tiempo",
v-model="newTask.time"
)
.control
button.button.is-info(@click="addTask") Agregar
.control
button.button.is-danger(@click="clearNewTask") Cancelar
.container
div Nombre: {{ name }}
div Tiempo total trabajado: {{ totalTime }}
table.table
thead
tr
th Titulo
th Tiempo
tbody
tr(v-for="(t, index) in tasks")
td {{ t.title }}
td {{ t.time }}
td
.control
button.button.is-info(@click="removeTask(index)") Eliminar
</template>
<script>
export default {
name: 'app',
data () {
return {
name: "",
tasks: [],
newTask: {
title: "",
time: ""
}
}
},
methods: {
addTask () {
console.debug("Agregando tarea...");
try {
const titleNewTask = this.newTask.title;
const timeNewTask = this.newTask.time;
if (!(titleNewTask && timeNewTask)) {
throw new Error("Campos titulo y tiempo son obligatorios!");
}
this.tasks.push({
title: titleNewTask,
time: parseInt(timeNewTask)
});
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.clearNewTask();
console.debug("Tarea agregada!");
} catch (err) {
console.error(`Error agregando tarea ${JSON.stringify(this.newTask)}`, err.stack);
}
},
clearNewTask (){
this.newTask = {
title: "",
time: ""
};
},
removeTask (taskIndex) {
this.tasks.splice(taskIndex, 1);
localStorage.setItem("tasks", JSON.stringify(this.tasks));
}
},
computed: {
totalTime () {
let totalTime = 0;
this.tasks.forEach(t => {
totalTime += t.time;
});
return totalTime;
}
},
created () {
this.tasks = JSON.parse(localStorage.getItem("tasks")) || [];
}
}
</script>
<style lang="scss">
@import './scss/main.scss'
</style>
Solucion del problema para el año 2020
<template>
<div>
<section class="section">
<nav class="navbar">
<div class="field has-addons">
<div class="control"><input class="input" type="text" placeholder="Find songs" v-model="new_task.title" /></div>
<div class="control"><input class="input" type="number" placeholder="Find songs" v-model="new_task.time" /></div>
<div class="control"><button class="button is-info" @click="addTask">Find</button></div>
<div class="control"><button class="button is-danger" @click="cancel">×</button></div>
<div class="control">
<button class="button">
<span class="is-size-7">Total hours worked: {{ totalTime }}</span>
</button>
</div>
</div>
</nav>
<div class="container custom">
<ul v-if="tasks.length !== 0">
<li v-for="(task, index) in tasks" :key="task.id">
<p>{{ task.title }} - {{ task.time }}</p>
<div class="control"><button class="button is-danger" @click="deleteTask(index)">×</button></div>
</li>
</ul>
<p v-else>La lista esta vacia</p>
</div>
</section>
</div>
</template>
<script>
export default {
name: "Test2",
data() {
return {
name: "",
tasks: [
{ title: "Job", time: 8 },
{ title: "Eat", time: 2 }
],
new_task: { title: "", time: null }
};
},
created() {
this.tasks = JSON.parse(localStorage.getItem("tasks")) || [];
},
methods: {
addTask() {
if (this.new_task.title && this.new_task.time) {
this.tasks.unshift(this.new_task);
this.new_task = { title: "", time: null };
localStorage.setItem("tasks", JSON.stringify(this.tasks));
}
},
deleteTask(index) {
this.tasks.forEach((element, i) => {
if (index == i) {
this.tasks.splice(i, 1);
localStorage.setItem("tasks", JSON.stringify(this.tasks));
}
});
},
cancel() {
this.new_task = { title: "", time: null };
}
},
computed: {
totalTime() {
let summation = 0;
this.tasks.forEach(element => {
summation += parseInt(element.time, 10);
});
return summation;
}
}
};
</script>
<style lang="scss">
@import "../scss/main.scss";
.input {
border: 1px solid black;
}
</style>
Mi version con uso de _lodash
<template lang="pug">
#app
h2 {{ name }}
input(type="text" placeholder="title" v-model="newTask.title" required)
input(type="number" placeholder="time in hours" v-model="newTask.time" required)
button(v-on:click="addTask()" class="button is-primary") Generar
button(v-on:click="cancel()" class="button is-danger") X
p(v-show="tasks.length === 0 ? true : false") No se han agregado tareas
ul
li(v-for="(t, index) in tasks" :key="index")
p {{ index }} {{ t.title }} - {{ t.time }}
button.button.is-danger(v-on:click="removeTask(index)") x
h5(v-show="tasks.length !== 0 ? true : false") Tiempo {{ totalTime }} horas
</template>
<script>
export default {
name: "App",
data() {
return {
name: "Lista de Tareas",
tasks: [],
newTask: {
title: "",
time: ""
}
};
},
created() {
this.tasks = JSON.parse(localStorage.getItem("tasks")) || [];
},
computed: {
totalTime() {
let tiempos = this._.map(this.tasks, "time");
let tiemposNum = this._.map(tiempos, this._.parseInt);
let totalTime = this._.sum(tiemposNum);
return totalTime;
}
},
methods: {
addTask() {
this.tasks.push({ title: this.newTask.title, time: this.newTask.time });
localStorage.setItem("tasks", JSON.stringify(this.tasks));
this.newTask.title = "";
this.newTask.time = "";
},
cancel() {
this.newTask.title = "";
this.newTask.time = "";
},
removeTask(ind) {
this.tasks.splice(ind, 1);
console.log(this.tasks);
}
}
};
</script>
<style lang="scss">
@import "@/assets/scss/main.scss";
</style>
<template>
<div id=“app” class=“row mt-5”>
<div class=“col-12”>
<h1>Gestor de Tareas</h1>
<p class=“h6”>Total de horas trabajadas {{totalTime}}</p>
</div>
<div class=“col-4”>
<input class=“form-control input-lg” type="text"
placeholder=“Nueva tarea” v-model=“newTask.title”>
</div>
<div class=“col-4”>
<input v-model=“newTask.time” class=“form-control” type=“number” placeholder=“0”>
</div>
<div class=“col-4”>
<a class=“btn btn-info btn-lg mr-2” @click=“addTask”> Agregar </a>
<a class=“btn btn-danger btn-lg” @click=“cancel” > Cancelar </a>
</div>
<table v-if="tasks.length > 0" class="table">
<thead>
<tr>
<th scope="col">Tarea</th>
<th scope="col">Horas</th>
<th scope="col">Eliminar</th>
</tr>
</thead>
<tbody>
<tr v-for="(task, index) in tasks" :key="index" >
<td>{{task.title}}</td>
<td>{{task.time}}</td>
<td><a class="btn btn-danger" v-on:click="removetask(index)">Eliminar</a></td>
</tr>
</tbody>
</table>
<h1 class="h1" v-else>No hay tareas</h1>
</div>
</template>
<script>
export default {
name: ‘App’,
data () {
return {
tasks: [],
newTask: {
title: ‘’,
time: 0
}
}
},
computed: {
totalTime () {
let total = 0
this.tasks.forEach(elem => {
total += parseInt(elem.time)
})
return total
}
},
created () {
this.tasks = JSON.parse(localStorage.getItem(‘tasks’)) || []
},
methods: {
addTask () {
if (this.newTask.title !== ‘’ && this.newTask.time > 0) {
this.tasks.push({ title: this.newTask.title, time: this.newTask.time })
localStorage.setItem(‘tasks’, JSON.stringify(this.tasks))
this.cancel ()
} else {
console.log(‘valor no aceptado’)
}
},
cancel () {
this.newTask.title = ''
this.newTask.time = 0
},
removetask (index) {
this.tasks.splice(index, 1)
localStorage.setItem(‘tasks’, JSON.stringify(this.tasks))
}
}
}
</script>
<style lang=“scss”>
@import “./scss/main.scss”;
</style>
Lo hice con bootstrap
<template>
<div id="app" class="row mt-6 mx-6">
<div class="container col-6">
<div class="input-group input-group-lg">
<input class="form-control input-lg" type="text"
placeholder="Nueva tarea" v-model="newtask.title">
</div>
<p class="h6">Total de horas {{totalhoras}}</p>
</div>
<select class="col-2 form-select form-select-lg mb-3" aria-label=".form-select-lg example" v-model="newtask.time">
<option value = "0" selected>Horas</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
<div class="col-4">
<a class="btn btn-info btn-lg mr-2" v-on:click="agregar"> Agregar </a>
<a class="btn btn-danger btn-lg" v-on:click="borrar" > Borrar lista </a>
</div>
<div class="coninater col-12 mt-3">
<ul>
<!-- <li v-for="t in tracks" v-bind:key="t">{{t.name}} - {{ t.artist}}</li>-->
</ul>
</div>
<table v-if="tasks.length > 0" class="table">
<thead>
<tr>
<th scope="col">Tarea</th>
<th scope="col">Horas</th>
<th scope="col">Eliminar</th>
</tr>
</thead>
<tbody>
<tr v-for="task in tasks" v-bind:key="task.title">
<td>{{task.title}}</td>
<td>{{task.time}}</td>
<td><a class="btn btn-danger" v-on:click="removetask(task)">Eliminar</a></td>
</tr>
</tbody>
</table>
<h1 class="h1" v-else>No hay tareas</h1>
</div>
</template>
<script>
// const reducer = (accumulator, currentValue) => accumulator + currentValue
export default {
name: 'App',
data () {
return {
name: '',
time: '',
tasks: [],
delete: 0,
newtask: {
title: '',
time: 0
}
}
},
computed: {
totalhoras () {
// this.newtask = this.tasks.time.slice()
let horas = 0
for (const task of this.tasks) {
horas += parseInt(task.time)
}
return horas
}
},
created () {
this.tasks = JSON.parse(localStorage.getItem('tasks')) || []
},
methods: {
agregar () {
if (!(this.tasks.find(tarea => tarea.title === this.newtask.title)) && this.newtask.time > 0) {
this.tasks.push({ title: `${this.newtask.title}`, time: `${this.newtask.time}` })
localStorage.setItem('tasks', JSON.stringify(this.tasks))
this.newtask = []
} else {
console.log('valor no aceptado')
}
},
borrar () {
this.tasks = []
},
removetask (titulo) {
this.delete = this.tasks.indexOf(titulo)
// console.log(this.tasks.indexOf(titulo))
this.tasks.splice(this.delete, 1)
localStorage.setItem('tasks', JSON.stringify(this.tasks))
}
}
}
</script>
<style lang="scss">
@import "./scss/main.scss";
</style>
Hola a todos!!
Creo que el diseño no esta chevere pero me gusto construir la funcionalidad…
Agregue un elemento de validación al input que se muestra si se intenta guardar con errores
😉
¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.