Shopware 6 sw-number-field: how to set id? - plugins

How do i set sw-number-field.id in custom plugin?
By default, the configuration of sw-number-field.id is a design violation.
This is observable at price fields on product detail page:
// sw-number-field.html.twig
<template #sw-field-input="{ identification, error, disabled, size, setFocusClass, removeFocusClass }">
<!-- eslint-disable-next-line vuejs-accessibility/form-control-has-label -->
<input
:id="identification"
Where does identification come from, or where should to set it?

You can use the name property which will also replace the auto-generated id.
<sw-number-field name="foobar" />
<!-- becomes -->
<input id="foobar" name="foobar" type="text" placeholder="" autocomplete="off">
By default it is set in src/app/component/form/field-base/sw-base-field/index.js
data() {
return {
id: utils.createId(),
};
},
computed: {
identification() {
if (this.name) {
return this.name;
}
return `sw-field--${this.id}`;
},
//...
}

Related

Vue Formulate validation for two fields at the same time

I'm currently building a form in Vue js and I'm using Vueformulate, the docs have various ways of validation however there is no validation method or implementation that for my use case. I would like the validation to call a custom function because this way I could check if Field1 or Field2 has a value. Is there an implementation like my psuedocode below? thanks in advance!
<FormulateForm #submit="onSubmit" #default="{ hasErrors }">
<FormulateInput
type="text"
label="Field1"
validation="customValidation"
/>
<FormulateInput
type="text"
label="Field2"
validation="customValidation"
/>
<FormulateInput
type="submit"
label="Submit"
input-class="btn btn-primary w-full"
:disabled="hasErrors"
/>
</FormulateForm>
//NOT REAL CODE
customValidation(formValues){
if(formValues.Field1 || formValues.Field2){
return true // CHECK IF EITHER FIELD1 OR FIELD 2 HAS VALUE IF SO MARK THE FIELD AS VALID WHICH ENABLES SUBMIT BUTTON
}
return false
}
You can declare a custom validation rule via <FormulateInput>.validationRules:
<script setup>
const validationRules = {
customValidation({ getFormValues }) {
// property names match the input names
const { field1, field2 } = getFormValues()
if (field1 || field2) {
return true
}
},
}
</script>
<template>
<FormulateInput
type="text"
label="Field1"
name="field1"
validation="customValidation"
:validationRules="validationRules"
/>
<FormulateInput
type="text"
label="Field2"
name="field2"
validation="customValidation"
:validationRules="validationRules"
/>
</template>
But FormulateForm assumes an error state unless all fields are touched (at least in my demo). Not sure how you could get around that.
demo

Form validation in Vue.js using computed property

I have a form that I need to validate. This is just one field that I have specified. I'm trying to validate it using computed property.
<input
type="text"
v-model="buyerName"
placeholder="Name"
autocomplete="on"
required
>
<span class="errorNotification" >{{validateName}}</span>
This is the computed property 'validateName' I'm using
computed: {
validateName(){
return (this.buyerName !== "" ? "" : "Enter your name");
}
}
This is how I am getting when the page is loaded. Is there a way to display the error message only when that field is in focus?
TIA
You can achieve it with v-if directive, set default value for the buyerName as null;
Your input field:
<input type="text"
name="name"
id="name"
v-model="buyerName()"
required>
<span v-if="errors" class="errorNotification">{{ errors }}</span>
You js code:
data:{
errors:null,
buyerName:null
},
methods:{
checkForm:function(e) {
this.errors = null;
if (this.buyerName!=null && this.buyerName!="") {
//your actions if form is valid
console.log("success");
} else {
this.errors = "Name required.";
}
e.preventDefault();
}
}
Check examples of validation in doc: https://v2.vuejs.org/v2/cookbook/form-validation.html

Get computed property and pass its value while editing another text field vue.js

I want to send over a computed property at the same time as editing a textfield so there is no button to "save" however I cannot work out how to get the property value from another field or from the computed data to pass over.
Here is my code so far, activeNote.id can be viewed in the template no problem but I want to pass its value whenever I type into the textarea
<template>
<div class="editor">
<form id="editForm">
<h2>Edit</h2>
<button #click="closeEdit()">Close</button>
<textarea
v-bind:value="activeNote.text"
#input="editNote"
class="form-control"
></textarea>
<input v-bind:value="activeNote.id" name="id" readonly />
</form>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
methods: {
// not sure this is best practice to dispatch from here
editNote(e) {
this.$store.dispatch('editNote', e)
// activeNote.id doesnt work here unfortunatly
this.$store.dispatch('noteId', activeNote.id)
//console.log(activeNote.id)
}
closeEdit() {
//console.log('emitclose')
this.$emit('closeEdit')
}
},
computed: mapState({
activeNote: state => state.activeNote
})
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
It was simple in the end so fyi the changed code that worked, adding this.
<template>
<div class="editor">
<form id="editForm">
<h2>Edit</h2>
<button #click="closeEdit()">Close</button>
<textarea
v-model="activeNote.text"
#input="editNote"
class="form-control"
></textarea>
<input v-bind:value="activeNote.id" name="id" readonly />
</form>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
methods: {
editNote(e) {
this.$store.dispatch('editNote', e)
this.$store.dispatch('noteId', this.activeNote.id)
},
closeEdit() {
this.$emit('closeEdit')
}
},
computed: mapState({
activeNote: state => state.activeNote
})
}
</script>

Vue reactive forms components communication

I have multiple form components, each form as a component. Now, I want to use same component for adding data and editing data. So what I am thinking to do is something like when the Post component receives a prop containing data that means it is in a "editing mode" and populate the fields with its data, if not it is in "create mode".
So how should I use v-model in my form fields?
Should I v-model each form field to a computed property (which has a getter and a setter) and the computed property would check if the data prop is empty and if not use its data to populate fields ? And in the computed property set method to update the prop ?
parent component
<post :data.sync="dataObject"></post>
child (Post) component
<template>
<div>
<form>
<input type="text" label="title" v-model="computedTitle" />
<input type="text" label="message" v-model="computedMessage" />
</form>
</div>
<input type="button" #click="submitted"
<template>
<script>
export default {
data(){
return{
post:{
title:null,
message:null
}
}
},
props:["data"],
computed:{
computedTitle:{
get(){
return data ? data.title : ''
},
set(computedTitle){
computedTitle = computedTitle // trying to update computed property value with the field value...
}
},
computedMessage:{...}
}
}
</script>
You can use watch to check data prop, if it's set then set to local post variable.
If created, then data is null, post.title and post.message are set to null
If updated, then data is not null, post.title is set to data.title and post.message to set to data.message
<template>
<div>
<form>
<input type="text" label="title" v-model="post.title" />
<input type="text" label="message" v-model="post.message" />
</form>
</div>
<input type="button" #click="submitted"
<template>
<script>
export default {
data() {
return{
post: {
title: null,
message: null
}
}
},
props:["data"],
watch: {
data: {
handler(newData) {
if (newData) {
this.post = {
title: newData.title,
message: newData.message
}
}
},
immediate: true // this makes watch is called when component created
}
}
}
</script>
Note that you should use immediate: true to make the watch's function called when component is created

Proper way of clearing forms without redux-form

This is my form
<form className="input-group" onSubmit={this.handleSubmit}>
<input className="form-control"
type="text"
placeholder="Insert name"
autofocus="true" />
<span className="input-group-btn">
<button type="submit" className={classNames}>Add</button>
</span>
</form>
This is my event handler:
handleSubmit(e) {
e.preventDefault();
let name = e.target[0].value;
if (name.length > 0) {
this.props.dispatch(createClassroom(name));
}
}
My question is:
what's the proper "redux way" to clearing the form after submitting it?
Do I need to dispatch a different action or should I use the existing createClassroom action?
Note: I'd rather not use redux-form package.
First, you have to make sure that the <input> is a controlled component by passing its respective value from the state:
const { classroom } = this.props;
// in return:
<input type="text" value={ classroom.name } />
Then, the form can be cleared by ideally submitting a RESET action that your classroom reducer acts upon:
const initialState = {};
function classroomReducer(state = initialState, action) {
switch (action.type) {
// ...
case 'RESET_CLASSROOM':
return initialState;
default:
return state;
}
}