I just wanted to fix the display of errors in the view page. It is being displayed as JSON format. How do I fix this?
Vue.component
<template>
<v-alert
dense
outlined
type="error"
>
{{ allerror }}
</v-alert>
...
...
</template>
<script>
data: () => ({
allerror: ''
}),
axios
.post('/api/section', { name, department_id })
.then(response => {
this.getSections()
this.snackbar.appear = true
this.snackbar.alert = response.data.alert
this.snackbar.icon = response.data.icon
this.$refs.form.reset()
})
.catch(error => this.allerror = error.response.data.errors)
</script>
there are 2 ways to go:
1 - Show specific errors on specific field by:
<v-text-field
label="Name"
v-model="name"
:error-messages="allerror.name"
></v-text-field>
2 - Show all error:
<v-alert
dense
outlined
type="error"
>
<ul>
<li v-for="(errors, field) in allerror">
{{ field }} //name of the field
//run second loop to display all errors for this field
<ul>
<li v-for="error in errors">
{{ error }}
</li>
</ul>
</li>
</ul>
</v-alert>
Add custom css class
.invalid-feedback {
width: 100%;
margin-top: 0.25rem;
font-size: 80%;
color: #e3342f;
}
Then bind invalid-feedback in the text field, if you are using laravel you can find invalid-feedback in app.css file
<v-text-field
v-model="form.email"
:rules="[rules.required, rules.emailRules]"
:class="{ 'is-invalid':
form.errors.has('email') }"
label="E-mail"
required
></v-text-field>
Related
What I am trying to do is to Design a new Vue/Inertia Login / Register modal on the frontend for the standard Vue scaffolding that comes with Laravel Breeze.
Exactly what I am trying to achieve is this:
Login / Register Button -> Clicked and a modal opens
The modal contains a header section where there is a "Login" tab and a "Register" tab, by default the login tab is selected. It then contains a body section that is a panel that switches between the "login.vue" file and the "register.vue" file.
It is from my understanding that I need to do the following:
Create a Vue file for the button that creates the modal that includes a vue file that houses the tabs and switching panel, that call the "Login" & "Register" Vue files.
I hope my understanding of the way that the Vue3.js framework handles things is correct.
I am very new to Laravel, and to Vue, so please bear with me.
My file structure is as follows
resources | js | Pages | Auth -> Login.vue (standard code in file)
resources | js | Pages | Auth -> Register.vue (standard code in file)
resources | js | Pages | Modal -> LoginRegister.vue
<script>
import Register from "./Auth/Register.vue";
import Login from "./Auth/Login";
export default {
data: function () {
return {
tabs: ["Login", "Register"],
selected: "Login",
};
},
components: {
Register,
Login,
},
};
</script>
<template>
<div>
<button
v-for="tab in tabs"
:key="tab"
#click="selected = tab;"
:class="['tab-btn', { active: selected === tab }]"
>
{{ tab }}
</button>
<component :is="selected" class="tab"></component>
</div>
</template>
or alternatively I have tried this code in the LoginRegister.vue too
<style>
.tab-btn {
padding: 6px 10px;
background: #ffffff;
cursor: pointer;
margin-bottom: 1rem;
border: 2px solid #cccccc;
outline: none;
}
.active {
border-bottom: 3px solid green;
background: whitesmoke;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
</style>
<script>
import Login from "./Auth/Login.vue";
import Register from "./Auth/Register.vue";
import PrimaryButton from "#/Components/PrimaryButton.vue";
export default { components: { Login, Register } };
</script>
<template>
<div>
<PrimaryButton v-on:click="showModal = true"
>Login / Register</PrimaryButton
>
<modal v-if="showModal" #close="showModal = false">
<div
class="modal fade"
id="myModal"
tabindex="-1"
role="dialog"
aria-labelledby="LoginRegisterModal"
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Login / Register</h4>
</div>
<div class="modal-body">
<ul class="nav nav-tabs">
<li role="presentation" class="active">
<a
href="#tab1"
aria-controls="home"
role="tab"
data-toggle="tab"
>Login</a
>
</li>
<li role="presentation">
<a
href="#tab2"
aria-controls="profile"
role="tab"
data-toggle="tab"
>Register</a
>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tab1">
<Login></Login>
</div>
<div role="tabpanel" class="tab-pane" id="tab2">
<Register></Register>
</div>
</div>
</div>
</div>
</div>
</div>
</modal>
</div>
</template>
I still have not worked out how to create a button that will launch this in a modal yet too, I know I am a long way off, but I would really appreciate guidance.
I found a solution which works well... the following code.
<script setup>
import { computed, onMounted, onUnmounted, watch } from 'vue';
const props = defineProps({
show: {
type: Boolean,
default: false,
},
maxWidth: {
type: String,
default: '2xl',
},
closeable: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['close']);
watch(() => props.show, () => {
if (props.show) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = null;
}
});
const close = () => {
if (props.closeable) {
emit('close');
}
};
const closeOnEscape = (e) => {
if (e.key === 'Escape' && props.show) {
close();
}
};
onMounted(() => document.addEventListener('keydown', closeOnEscape));
onUnmounted(() => {
document.removeEventListener('keydown', closeOnEscape);
document.body.style.overflow = null;
});
const maxWidthClass = computed(() => {
return {
'sm': 'sm:max-w-sm',
'md': 'sm:max-w-md',
'lg': 'sm:max-w-lg',
'xl': 'sm:max-w-xl',
'2xl': 'sm:max-w-2xl',
}[props.maxWidth];
});
</script>
<template>
<teleport to="body">
<transition leave-active-class="duration-200">
<div v-show="show" class="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50" scroll-region>
<transition
enter-active-class="ease-out duration-300"
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-active-class="ease-in duration-200"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<div v-show="show" class="fixed inset-0 transform transition-all" #click="close">
<div class="absolute inset-0 bg-gray-500 opacity-75" />
</div>
</transition>
<transition
enter-active-class="ease-out duration-300"
enter-from-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enter-to-class="opacity-100 translate-y-0 sm:scale-100"
leave-active-class="ease-in duration-200"
leave-from-class="opacity-100 translate-y-0 sm:scale-100"
leave-to-class="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div v-show="show" class="mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto" :class="maxWidthClass">
<slot v-if="show" />
</div>
</transition>
</div>
</transition>
</teleport>
</template>
Then use headless ui for the switching tabs, works well.
I am getting menu like below from api request with laravel vue.
{"data":[{"id":67,"slug":"link","name":"Dashboard","href":"\/","hasIcon":true,"icon":"mdi mdi-home-account","iconType":"coreui","sequence":1}]}
and my componant is below and displaying well but click event not woking , when i mannully put this json data --> menu then every thing working good. so i think mounted is not working as per expectation in this senario. i tried like passing it from another component as props , then putting it in data --> menu but not working as well any idea ?
<template>
<div class="vertical-menu">
<div data-simplebar="init" class="h-100 mm-show">
<div id="sidebar-menu">
<ul class="metismenu list-unstyled" id="side-menu">
<li v-for="(item, index) in menu" :key="index">
<router-link :to="item.href ? item.href : ''" :class="item.slug === 'dropdown' ? 'has-arrow' : '' ">
<i :class="item.icon"></i>
<span :data-key="item.datakey">{{item.name}}</span>
</router-link>
<ul class="sub-menu" aria-expanded="false">
<li v-for="subItem in item.elements" :key="subItem.name" >
<router-link :to="subItem.href ? subItem.href : ''"> {{subItem.name}} </router-link>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name:"DashboardLeftBar",
props:['app_base_url'],
data(){
return {
menu: null
}
},
mounted(){
this.menuSideBar();
},
methods:{
menuSideBar(){
let token= localStorage.getItem('jwt');
let crl=JSON.parse(localStorage.getItem('user')).crl;
axios.post(myconstant.APPICATION_API_URL+'/getmenu',{
token: token,
crl: crl,
}).then((response) => {
this.menu = response.data.data;
});
}
}
}
</script>
I have a dynamically created checkbox list and I'm having trouble to check the some trues according to a pre-defined list.
HTML:
<div class="row">
<div class="example-container col-md-6">
<div *ngFor="let atribuicao of atribuicoesOcorrencia" formArraylName="inputAtribuicaoOcorrencia">
<mat-checkbox [value]="atribuicao.id" (change)="onChange(atribuicao, $event)">
<div style="white-space: pre-wrap;">
{{ atribuicao.descricao }}
</div>
</mat-checkbox>
</div>
</div>
</div>
CLASS TS:
I try populate formControl name inputAtribuicaoOcorrencia in a list, in this case
the only one checekd was id 3, but nothing happens
this.atribuicoesOcorrencia.forEach(listAtibuicoes=> {
ocorrencia.atribuicoesDTO.forEach(x => {
if(listAtibuicoes.id == x.id){
this.formCadastro.get('inputAtribuicaoOcorrencia').setValue('checked');
}
});
});
CLASS TS2:
Or the code bellow for one ID checked only
this.formCadastro.patchValue({
inputAtribuicaoOcorrencia: 'checked',
});
You need to use the [checked] attribute for the mat-checkbox
// example
<mat-checkbox
[value]="atribuicao.id"
[checked]="atribuicao.id" // This is what you need to add. If id is there, it will get checked
(change)="onChange(atribuicao, $event)"
>
<div style="white-space: pre-wrap;">
{{ atribuicao.descricao }}
</div>
</mat-checkbox>
I would like to display text area resource field content always without showing option "Show Content" or display it by default.
Is it possible?
As of v1.1.4
There is now an option to always show.
Textarea::make('Title')->alwaysShow()
As of v1.0.19
You cannot. If you take a look at the TextareaField.vue (nova/resources/js/components/Detail/TextareaField.vue):
<template>
<panel-item :field="field">
<template slot="value">
<excerpt :content="field.value" />
</template>
</panel-item>
</template>
Then if you take a look at Excerpt.vue (nova/resources/js/components/Excerpt.vue):
<div v-if="hasContent">
<div v-if="expanded" class="markdown leading-normal" v-html="content" />
<a
#click="toggle"
class="cursor-pointer dim inline-block text-primary font-bold"
:class="{ 'mt-6': expanded }"
aria-role="button"
>
{{ showHideLabel }}
</a>
</div>
And the props of the vue:
props: {
content: {
type: String,
},
},
data: () => ({ expanded: false }),
There's no option to pass the expanded attribute.
I have below html:
<li>
<div class="w3l_banner_nav_right_banner1" style="background:url('./assets/images/2.jpg') no-repeat 0px 0px;">
<h3>Make your <span>food</span> with Spicy.</h3>
<div class="more">
Shop now
</div>
</div>
</li>
Problem:
I want to replace image url /assets/images/2.jpg with dynamic variable like {{ article.uri }}.
I tried with several way from below ref:
Attribute property binding for background-image url in Angular 2
How to add background-image using ngStyle (angular2)?
Tried so far:
<li *ngFor="let article of arr;let i=index;">
<div *ngIf="i == 0" class="w3l_banner_nav_right_banner" [ngStyle]="{ 'background-url': 'url('+article.uri+')'} no-repeat 0px 0px;">
<h3>Make your <span>food</span> with Spicy.</h3>
<div class="more">
Shop now1
</div>
</div>
</li>
I am using Angular 4.1.3.
background-url is incorrect CSS, use background or background-image instead.
Here is an example of correct syntax:
<div [ngStyle]="{'background': '#fff url(' + article.uri + ') no-repeat 0 0'}"></div>
Your full example would look like this:
<li *ngFor="let article of arr; let i=index;" >
<div *ngIf="i == 0"
class="w3l_banner_nav_right_banner"
[ngStyle]="{'background': '#fff url(' + article.uri + ') no-repeat 0 0'}" >
<h3> Make your <span>food</span> with Spicy. </h3>
<div class="more">
Shop now1
</div>
</div>
</li>
If you're getting your background image from a remote source or a user input you will need to have angular sanitize the url. In your component you will want to add the following bits of code...
import { DomSanitizer } from '#angular/platform-browser';
export class YourComponent {
constructor(private _sanitizer: DomSanitizer) { }
public sanitizeImage(image: string) {
return this._sanitizer.bypassSecurityTrustStyle(`url(${image})`);
}
}
Try setting your HTML to this...
<li *ngFor="let article of arr;let i=index;">
<div *ngIf="i == 0" class="w3l_banner_nav_right_banner" [style.background-image]="sanitizeImage(article.uri)">
<h3>Make your <span>food</span> with Spicy.</h3>
<div class="more">
Shop now1
</div>
</div>
</li>
And apply the no-repeat 0px 0px; in some class you attach to the div.
The correct answer is [style.background-image]="'url(' + article.uri + ')'"
but if you are using ngFor for carousel, make sure you have added class 'active' properly.
This code will NOT working:
<div class="carousel-item active"
*ngFor="let article of arr;"
[style.background-image]="'url(' + article.uri + ')'"></div>
You should use 'active' class for first item only!
<div class="carousel-item"
*ngFor="let article of arr; let i = index;"
[ngClass]="{'active': i === 0}"
[style.background-image]="'url(' + article.uri + ')'"></div>
you can use it by adding url path in a single variable.
for example
bgImageVariable="www.domain.com/path/img.jpg";
[ngStyle]="{'background-image': 'url(' + bgImageVariable + ')'}"
Working for Angular 8+ (Power of template literals):
In component, define ngStyle object var (here called as styles, initialised in constructor):
const bgImageUrl = 'assets/images/dot-grid.png'
const styles = {
backgroundImage: `url(${bgImageUrl})`
};
In template, assign this as ngStyle
<div [ngStyle]="styles"><!-- your content --></div>
In my case the following syntax worked:
<ion-slide *ngFor="let page of pages">
<div class="cardImage" style.background-image="url('{{ page.imageUrl }}')"></div>
</ion-slide>
Ionic CLI : 6.16.3
This works fine for me:
js file:
path = 'url(../assets/about.png)';
array:
string[] = [this.path];
and HTML file:
<div *ngFor="let item of array" [ngStyle]="{'background-image': item}">
To solve this, the correct syntax is
<div class="modalContainer"
ng-style="{'background-image': 'url(' + selectedMeal.url + ')'}">
Mark answer if it helps.