Laravel/vuejs Change boolean value from 0 to 1 - laravel

I have a question I need to create a 2 factor authentication only now the value of a colum in the database will be set to true. He is default to false. I know the database adds this as tinyint so the value should be switched to 1.
So i have try something but didnt work.. im very new with laravel and vuejs. so its hard for me. I hope one of you can help me out of this struggle
My 2 factor vue. So you can see the v-switch thats the button..
<template>
<v-container class="user-form-lime" fluid grid-list-xl>
<v-form>
<v-layout row wrap>
<v-flex xs12 md6>
<v-switch v-model="tfaEnabled"
label="Tweefactor authenticatie"
name="tfaEnabled"
prepend-icon="lock"
#change="change" />
</v-flex>
<v-flex xs12 md6>
<v-text-field v-if="tfaEnabled"
v-model="google2fa.token"
label="Token"
:rules="[rules.required]"
type="text" />
</v-flex>
</v-layout>
<v-layout row wrap>
<v-flex xs12>
<v-btn color="success" #click="submit">
Opslaan
</v-btn>
</v-flex>
</v-layout>
</v-form>
</v-container>
</template>
<script>
export default {
name: 'UserForm2fa',
props: {
id: { type: Number, required: true }
},
data() {
return {
tfaEnabled: false,
google2fa: {
token: '',
},
rules: {
required: val => !!val || 'Dit veld mag niet leeg zijn',
}
};
},
methods: {
changeStatus() {
this.$emit( 'change', this.tfaEnabled );
},
submit() {
this.$emit('submit', this.token)
}
}
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
My controller function:
public function update2faStatus( Update2faStatus $request ) {
$user = User::findOrFail( $request->id );
$tfaEnabled = $request->input('tfaEnabled', false);
$user->tfaEnabled = $tfaEnabled;
$user->save();
}
and my Method for this:
toggle2fa( status ) {
this.$store.dispatch( 'update2faStatus' )
.then( () => this.$store.dispatch('addMessage', { success: true, content: ['2 Factor authenticatie is ingeschakeld.'] } ) )
.catch( error => this.$store.dispatch( 'addMessage', { success: false, content: error.response.data} ))
},

Its because you have not defined any method with name change(). #change event expects a method named change() in your code. But I guess you are trying to execute changeStatus() method when toggle button is changed. Changing your code to #change="changeStatus()" should fix the problem.

Related

Submit Vuetify form with the enter button

Thought this would be straight forward but it isn't. With vuetify forms how do I bind a form to the enter button so that it's submit function is invoked with the enter button?
Figures I'd find a work around as soon as I posted the question. I found the answer here:
https://github.com/vuetifyjs/vuetify/issues/1545
Basically I had to add an event listener to the component to attach the enter key press to my authenticate method. Here is the component in questions:
<template>
<v-card>
<v-card-title>
<span class="headline">Login</span>
</v-card-title>
<v-form v-model="isValid">
<v-card-text>
<v-container>
<v-row>
<v-col cols="12">
<v-text-field
v-model="username"
label="User Name"
prepend-icon="mdi-account circle"
:rules="userNameRequired"
required
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
v-model="password"
label="Password"
:type="showPassword ? 'text' : 'password'"
prepend-icon="mdi-lock"
:append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
#click:append="showPassword = !showPassword"
:rules="passwordRequired"
required
></v-text-field>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text #click="close"> Close </v-btn>
<v-btn color="blue darken-1" text #click="authenticate" :disabled="!isValid">
Login
</v-btn>
</v-card-actions>
</v-form>
</v-card>
</template>
<script>
import { authenticationService } from "../services/authenticationService/authentication.service";
import User from "../models/user";
export default {
name: "LoginForm",
props: ["userForAuthentication"],
data: () => ({
username: "",
password: "",
user: {},
isValid: true,
showPassword: false,
userNameRequired: [(v) => !!v || "User Name is required"],
passwordRequired: [(v) => !!v || "Password is required"],
}),
methods: {
async authenticate() {
try {
const response = await authenticationService.authenticateUser(
this.$data.username,
this.$data.password
);
if (response.status === 200) {
this.$data.user.shallowClone(response.data.user);
await this.resetData();
this.$emit(
"user-logging-in-event",
this.$data.user,
response.data.token
);
this.$toasted.success(`${this.$data.user.fullName} is logged in.`, {
duration: 3000,
});
} else if (response.status === 400) {
this.$toasted.error("Username or Password is incorrect.", {
duration: 3000,
});
} else {
this.$toasted.error(
"An error occurred while trying to authenticate the user",
{
duration: 3000,
}
);
}
} catch (error) {
this.$toasted.error(error, {
duration: 3000,
});
}
},
close() {
this.$emit("user-logging-in-event", null, null);
},
async resetData() {
this.$data.username = "";
this.$data.password = "";
},
},
mounted() {
let self = this;
window.addEventListener("keyup", function (event) {
if (event.keyCode === 13) {
self.authenticate();
}
});
this.$data.user = new User();
this.$data.user.shallowClone(this.$props.userForAuthentication);
},
};
</script>

Vuetify v-combobox validations not working

I have a Vuetify(v. 1.9.0) v-combobox with validation that at least one item should be selected from the menu. For some reason the validation is not triggered and there are no errors in the console.
<v-combobox
multiple
item-text="name"
item-value="id"
:items="items"
:rules="[rules.required]"
></v-combobox>
<script>
export default {
data: () => ({
rules: {
required: value =>
!!value || "Required."
}
})
}
</script>
What am I missing?
Try this example:
<template>
<v-app>
<v-content>
<v-form ref="form">
<div>
<v-combobox
multiple
item-text="name"
item-value="id"
:items="items"
:rules="[required]"
v-model="selected"
/>
selected = {{ selected }}
</div>
<div>
<v-btn #click="$refs.form.validate()">Validate</v-btn>
</div>
</v-form>
</v-content>
</v-app>
</template>
<script>
export default {
name: 'app',
data: () => ({
selected: null,
items: [
{ id: 1, name: 'Option 1' },
{ id: 2, name: 'Option 2' },
{ id: 3, name: 'Option 3' },
],
}),
methods: {
required(value) {
if (value instanceof Array && value.length == 0) {
return 'Required.';
}
return !!value || 'Required.';
},
},
};
</script>

Vue component does not render and ignores props

I am having a problem with a Vue component which should just show a simple dialog, the component looks like this:
<template>
<v-layout row justify-center>
<v-dialog
v-model="show"
max-width="290"
:persistent="persistent"
>
<v-card>
<v-card-title class="headline grey lighten-2">{{header}}</v-card-title>
<v-card-text v-html="text">
{{text}}
</v-card-text>
<v-card-actions>
<v-layout>
<v-flex xs6 md6 lg6 class="text-xs-center">
<v-btn block
color="primary"
flat
#click="closeDialog(true)"
>
{{agree_button_text}}
</v-btn>
</v-flex>
<v-flex xs6 md6 lg6 class="text-xs-center">
<v-btn block
color="warning"
flat
#click="closeDialog(false)"
>
{{abort_button_text}}
</v-btn>
</v-flex>
</v-layout>
</v-card-actions>
</v-card>
</v-dialog>
</v-layout>
</template>
<script>
export default {
props:
{
persistent:
{
type: Boolean,
required: false,
default: false
},
header:
{
type: String,
required: false,
default: ""
},
text:
{
type:String,
required: false,
default:""
},
abort_button_text:
{
type: String,
required: false,
default:"Avbryt"
},
agree_button_text:
{
type: String,
required: false,
default: "OK"
},
value:
{
}
},
data ()
{
return {
show: this.value
}
},
methods:
{
closeDialog:
function(retval)
{
this.show = false;
this.$emit('close-dialog-event',retval);
}
}
}
</script>
In app.js I have added the following:
require('./bootstrap');
import babelPolyfill from 'babel-polyfill';
import Vuetify from 'vuetify'
window.Vue = require('vue');
var vueResource = require('vue-resource');
window.socketIo = require('vue-socket.io');
Vue.use(vueResource);
Vue.use(Vuetify);
Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name="csrf-token"]').attr('content');
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
Vue.component('simple-dialog', require('./components/common/SimpleDialog.vue'));
And on the page where I use the component I have:
<div id="overview">
<simple-dialog show="true"
:header="dialog_header"
:text="dialog_message"
#close-dialog-event="display_dialog = false"></simple-dialog>
<v-app>
<v-content>
<v-container>
FOO AND BAR
</v-container>
</v-content>
</v-app>
</div>
I don't get any errors that the component is not loaded.
And if I try to change the name of the component in the app.js file and then try to load the component it throws an error that the component can not be found. So in others words it seems that it loads successfully. However, if I change the name of the props, e.g. changing
<simple-dialog show="true"
:header="dialog_header"
:text="dialog_message"
#close-dialog-event="display_dialog = false"></simple-dialog>
to
<simple-dialog show_bla="true"
:asdasd="dialog_header"
:asdasd="dialog_message"
#close-dialog-event="display_dialog = false"></simple-dialog>
it does not care. It does not even throw an error about that those props either does not exists or are invalid. The javascript used by the page:
var app = new Vue({
el: '#overview',
data:
{
display_dialog:true,
dialog_header:'',
dialog_message:'',
},
methods:
{
}
});
What could the problem be? Thanks for any help!
Well, When you're sending the value to the component and your prop show is initialized as an empty object.
replace
value: {}
to
value
or
the pass default value to false
value: {
type: Boolean
default: false
}
Hope this helps!

Binding a v-data-table to a props property in a template

I have a vue component which calls a load method returning a multi-part json object. The template of this vue is made up of several sub-vue components where I assign :data="some_object".
This works in all templates except for the one with a v-data-table in that the v-for process (or the building/rendering of the v-data-table) seems to kick-in before the "data" property is loaded.
With an npm dev server if I make a subtle change to the project which triggers a refresh the data-table then loads the data as I expect.
Tried various events to try and assign a local property to the one passed in via "props[]". Interestingly if I do a dummy v-for to iterate through or simply access the data[...] property the subsequent v-data-table loads. But I need to bind in other rules based on columns in the same row and that doesn't work.
Parent/main vue component:
...
<v-flex xs6 class="my-2">
<ShipViaForm :data="freight"></ShipViaForm>
</v-flex>
<OrderHeaderForm :data="orderheader"></OrderHeaderForm>
<v-flex xs12>
<DetailsForm :data="orderdet" :onSubmit="submit"></DetailsForm>
</v-flex>
...
So in the above the :data property is assigned from the result below for each sub component.
...
methods: {
load(id) {
API.getPickingDetails(id).then((result) => {
this.picking = result.picking;
this.freight = this.picking.freight;
this.orderheader = this.picking.orderheader;
this.orderdet = this.picking.orderdet;
});
},
...
DetailsForm.vue
<template lang="html">
<v-card>
<v-card-title>
<!-- the next div is a dummy one to force the 'data' property to load before v-data-table -->
<div v-show="false">
<div class="hide" v-for='header in headers' v-bind:key='header.product_code'>
{{ data[0][header.value] }}
</div>
</div>
<v-data-table
:headers='headers'
:items='data'
disable-initial-sort
hide-actions
>
<template slot='items' slot-scope='props'>
<td v-for='header in headers' v-bind:key='header.product_code'>
<v-text-field v-if="header.input"
label=""
v-bind:type="header.type"
v-bind:max="props.item[header.max]"
v-model="props.item[header.value]">
</v-text-field>
<span v-else>{{ props.item[header.value] }}</span>
</td>
</template>
</v-data-table>
</v-card-title>
</v-card>
</template>
<script>
import API from '#/lib/API';
export default {
props: ['data'],
data() {
return {
valid: false,
order_id: '',
headers: [
{ text: 'Order Qty', value: 'ord_qty', input: false },
{ text: 'B/O Qty', value: 'bo_qty', input: false },
{ text: 'EDP Code', value: 'product_code', input: false },
{ text: 'Description', value: 'product_desc', input: false },
{ text: 'Location', value: 'location', input: false },
{ text: 'Pick Qty', value: 'pick_qty', input: true, type: 'number', max: ['ord_qty'] },
{ text: 'UM', value: 'unit_measure', input: false },
{ text: 'Net Price', value: 'net_price', input: false },
],
};
},
mounted() {
const { id } = this.$route.params;
this.order_id = id;
},
methods: {
submit() {
if (this.valid) {
API.updateOrder(this.order_id, this.data).then((result) => {
console.log(result);
this.$router.push({
name: 'Orders',
});
});
}
},
clear() {
this.$refs.form.reset();
},
},
};
</script>
Hopefully this will help someone else who can't see the forest for the trees...
When I declared the data() { ... } properties in the parent form I initialised orderdet as {} instead of [].

How to wire up external data in Vuetify datatables

I have just started with Vue and found Vuetify ( and very impressed ) . I'm a bit of a newbie with node.js as well but some experience.
I am trying to find some examples on loading data from external API's into the vuetify datagrid - CRUD type stuff, reasonably large amounts of data paginated. The documentation in Vuetify is a little lacking in this regard. Should I be using Vuex?
If you want to call external API using REST, you'll need to use axios, which is a NPM package allowing you to make GET, POST and all that kind.
Let's use this online working API for our example. First, you need to get your data by calling this API. A good tutorial on Internet will show you more details, but let's use this code.
this.todos = axios.get('https://jsonplaceholder.typicode.com/todos/')
.then(response => { this.todos = response.data })
.catch(error => { console.log(error)});
Then you just have to use the datatable like in the documentation. Here is a CodePen to help you see, briefly, how I made the API call and then displayed it. It all comes from the official documentation, just modified to call a REST API. I'll put the code also here, in order to save it for future readers too.
<div id="app">
<v-app id="inspire">
<div>
<v-toolbar flat color="white">
<v-toolbar-title>Todos CRUD</v-toolbar-title>
<v-divider
class="mx-2"
inset
vertical
></v-divider>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="500px">
<v-btn slot="activator" color="primary" dark class="mb-2">New Item</v-btn>
<v-card>
<v-card-title>
<span class="headline">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.userId" label="User ID"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.id" label="ID"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-text-field v-model="editedItem.title" label="Title"></v-text-field>
</v-flex>
<v-flex xs12 sm6 md4>
<v-checkbox v-model="editedItem.completed" label="Completed?"></v-checkbox>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" flat #click="close">Cancel</v-btn>
<v-btn color="blue darken-1" flat #click="save">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
<v-data-table
:headers="headers"
:items="todos"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td class="text-xs-right">{{ props.item.userId }}</td>
<td class="text-xs-right">{{ props.item.id }}</td>
<td class="text-xs-right">{{ props.item.title }}</td>
<td class="text-xs-right">{{ props.item.completed }}</td>
<td class="justify-center layout px-0">
<v-icon
small
class="mr-2"
#click="editItem(props.item)"
>
edit
</v-icon>
<v-icon
small
#click="deleteItem(props.item)"
>
delete
</v-icon>
</td>
</template>
<template slot="no-data">
<v-btn color="primary" #click="initialize">Reset</v-btn>
</template>
</v-data-table>
</div>
</v-app>
</div>
And then the associated JS.
new Vue({
el: '#app',
data: () => ({
dialog: false,
headers: [
{
text: 'User ID',
align: 'left',
sortable: false,
value: 'userId',
width: '10'
},
{ text: 'ID', value: 'id', width: '10' },
{ text: 'Title', value: 'title' },
{ text: 'Completed', value: 'completed' }
],
todos: [],
editedIndex: -1,
editedItem: {
userId: 0,
id: 0,
title: '',
completed: false
},
defaultItem: {
userId: 0,
id: 0,
title: '',
completed: false
}
}),
computed: {
formTitle () {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
}
},
watch: {
dialog (val) {
val || this.close()
}
},
created () {
this.initialize()
},
methods: {
initialize () {
this.todos = axios.get('https://jsonplaceholder.typicode.com/todos/')
.then(response => { this.todos = response.data })
.catch(error => { console.log(error)});
},
editItem (item) {
this.editedIndex = this.todos.indexOf(item)
this.editedItem = Object.assign({}, item)
this.dialog = true
},
deleteItem (item) {
const index = this.todos.indexOf(item)
confirm('Are you sure you want to delete this item?') && this.todos.splice(index, 1)
},
close () {
this.dialog = false
setTimeout(() => {
this.editedItem = Object.assign({}, this.defaultItem)
this.editedIndex = -1
}, 300)
},
save () {
if (this.editedIndex > -1) {
Object.assign(this.todos[this.editedIndex], this.editedItem)
} else {
this.todos.push(this.editedItem)
}
this.close()
}
}
})

Resources