Web Component Input radio not in a group - input

I have the WC <m-form> witch is the wraper for my form and the input fields.
In the renderHTML() of m-form i do this:
renderHTML() {
this.loadChildComponents().then(children => {
Array.from(this.root.querySelectorAll('input'))
.filter(i => i.getAttribute('type') != "hidden").forEach(input => {
const label = this.root.querySelector(`label[for=${input.getAttribute("name")}]`)
const aInput = new children[0][1](input, label, { namespace: this.getAttribute('namespace') || ''})
aInput.setAttribute('type', input.getAttribute('type'))
input.replaceWith(aInput)
})
})
}
This wraps <input> and <label> in an <a-input> WC.
But when I want to do the same with
<input type="radio" id="gender1" name="gender" value="herr">
<label for="gender1">Herr</label>
<input type="radio" id="gender2" name="gender" value="frau">
<label for="gender2">Frau</label>
they are not in a group.
What can i do to get them grouped together but also in the <a-input>?
Here is the Code on the site and what got rendered out.

shadowDOM encapsulates CSS, HTML and behavior
Both you inputs are in shadowDOM. That is like putting them into 2 different IFRAMEs.
They have no clue another input exists
Remove shadowDOM
or, loads more work, add Events to make the inputs communicate with each other

Related

Binding getter array to checkbox group

I have a two page form so I am trying to mix submitting data to the server as well as making use of vuex. So on page one, I have a simple form which contains a group of checkboxes (removed layout and styling to reduce code)
<b-form #submit.stop.prevent="onSubmit">
<b-form-group>
<input v-model="$v.form.checkboxGroup.$model" type="checkbox" name="checkbox1" value="1">
<input v-model="$v.form.checkboxGroup.$model" type="checkbox" name="checkbox2" value="2">
<input v-model="$v.form.checkboxGroup.$model" type="checkbox" name="checkbox3" value="3">
</b-form-group>
<button class="btn try-btn" type="submit">Submit</button>
</b-form>
Essentially, when submitted, I send the form data to my repository so it can be saved on the backend. If this is successful, I call the following method
handleSubmitSuccess (response) {
if (response.data.action === 'next_step') {
this.$store.dispatch('createCheckboxData', this.$v.form.$model)
return
}
}
This method sets the checkbox data in my store and routes the user to the next page (removed this part). So all of this is fine, seems to work well.
So when on page two, I have a button that can take you back to page one. My idea is that if this happens, I use the previously checked data in the store to auto check the previously selected checkbox. As such, on page one I added a computed method
computed: {
checkboxData () {
return this.$store.getters.checkboxData
}
}
Now if I output checkboxData to the console, it seems to be an Observer object
[{…}, __ob__: Observer]
0:
checkboxData: Array(2)
0: "1"
1: "3"
length: 2
So the above shows that previously, the first and second checkboxes were checked.
My question is how can I now use this data to auto-check my checkboxes. I have seen some examples online, but they do not seem to work.
Thanks
The way you use Vue is a little different to me so you might have to change this but, basically, you can set your v-model to whatever array is set in the Vuex store and it will set those checkboxes to true:
new Vue({
el: "#app",
data: {
checkbox: [],
vuexData: ['1', '3']
},
mounted() {
this.checkbox = this.vuexData;
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input v-model="checkbox" type="checkbox" name="checkbox1" value="1">
<input v-model="checkbox" type="checkbox" name="checkbox2" value="2">
<input v-model="checkbox" type="checkbox" name="checkbox3" value="3">
{{ checkbox }}
</div>

Passing an event and additional variable in React Native

I'm currently working on a react native project using expo.
I have an input
<Input type="text" onChange={this.onValueChange} />
When a change is made in the type I can console.log like so:
onValueChange(event) {
console.log(event.nativeEvent.text);
}
However I need to pass an additional variable to this method so I can identify it.
I tried this:
onValueChange(event, inputArea) {
console.log(event.nativeEvent.text);
}
And to pass it the variables I did this:
<Input type="text" onChange={this.onValueChange(event, 'nine')} />
Event now does nto function. I also tried:
<Input type="text" onChange={this.onValueChange('nine')} />
My outcome is that I need to capture the input text AND pass a variable.
You can use an high order function.
onChangeHandler = (foo, bar) => event => {
console.log(foo) // should display nine
console.log(bar) // should display whatever
// handle your event with your native variable
}
<Input type=« text » onChange={this.onChangeHandler(‘nine’, ‘whatever’)} />
Just saw how to do this.
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

Getting form data on submit?

When my form is submitted I wish to get an input value:
<input type="text" id="name">
I know I can use form input bindings to update the values to a variable, but how can I just do this on submit. I currently have:
<form v-on:submit.prevent="getFormValues">
But how can I get the value inside of the getFormValues method?
Also, side question, is there any benefit to doing it on submit rather than updating variable when user enters the data via binding?
The form submit action emits a submit event, which provides you with the event target, among other things.
The submit event's target is an HTMLFormElement, which has an elements property. See this MDN link for how to iterate over, or access specific elements by name or index.
If you add a name property to your input, you can access the field like this in your form submit handler:
<form #submit.prevent="getFormValues">
<input type="text" name="name">
</form>
new Vue({
el: '#app',
data: {
name: ''
},
methods: {
getFormValues (submitEvent) {
this.name = submitEvent.target.elements.name.value
}
}
}
As to why you'd want to do this: HTML forms already provide helpful logic like disabling the submit action when a form is not valid, which I prefer not to re-implement in Javascript. So, if I find myself generating a list of items that require a small amount of input before performing an action (like selecting the number of items you'd like to add to a cart), I can put a form in each item, use the native form validation, and then grab the value off of the target form coming in from the submit action.
You should use model binding, especially here as mentioned by Schlangguru in his response.
However, there are other techniques that you can use, like normal Javascript or references. But I really don't see why you would want to do that instead of model binding, it makes no sense to me:
<div id="app">
<form>
<input type="text" ref="my_input">
<button #click.prevent="getFormValues()">Get values</button>
</form>
Output: {{ output }}
</div>
As you see, I put ref="my_input" to get the input DOM element:
new Vue({
el: '#app',
data: {
output: ''
},
methods: {
getFormValues () {
this.output = this.$refs.my_input.value
}
}
})
I made a small jsFiddle if you want to try it out: https://jsfiddle.net/sh70oe4n/
But once again, my response is far from something you could call "good practice"
You have to define a model for your input.
<input type="text" id="name" v-model="name">
Then you you can access the value with
this.name inside your getFormValues method.
This is at least how they do it in the official TodoMVC example: https://v2.vuejs.org/v2/examples/todomvc.html (See v-model="newTodo" in HTML and addTodo() in JS)
Please see below for sample solution, I combined the use of v-model and "submitEvent" i.e. <input type="submit" value="Submit">. Used submitEvent to benefit from the built in form validation.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/vue"></script>
</head>
<body>
<div id="app">
<form #submit.prevent="getFormValues">
<div class="form-group">
<input type="email" class="form-control form-control-user"
v-model="exampleInputEmail"
placeholder="Enter Email Address...">
</div>
<div class="form-group">
<input type="password" class="form-control"
v-model="exampleInputPassword" placeholder="Password"> </div>
<input type="submit" value="Submit">
</form>
</div>
<script>
const vm = new Vue({
el: '#app',
methods: {
getFormValues (submitEvent) {
alert("Email: "+this.exampleInputEmail+" "+"Password: "+this.exampleInputPassword);
}
}
});
</script>
</body>
</html>
The other answers suggest assembling your json POST body from input or model values, one by one. This is fine, but you also have the option of grabbing the whole FormData of your form and whopping it off to the server in one hit. The following working example uses Vue 3 with Axios, typescript, the composition API and setup, but the same trick will work anywhere.
I like this method because there's less handling. If you're old skool, you can specify the endpoint and the encoding type directly on the form tag.
You'll note that we grab the form from the submit event, so there's no ref, and no document.getElementById(), the horror.
I've left the console.log() there to show that you need the spread operator to see what's inside your FormData before you send it.
<template>
<form #submit.prevent="formOnSubmit">
<input type="file" name="aGrid" />
<input type="text" name="aMessage" />
<input type="submit" />
</form>
</template>
<script setup lang="ts">
import axiosClient from '../../stores/http-common';
const formOnSubmit = (event: SubmitEvent) => {
const formData = new FormData(event.target as HTMLFormElement);
console.log({...formData});
axiosClient.post(`api/my-endpoint`, formData, {
headers: {
"Content-Type": "multipart/form-data",
}
})
}
</script>

knockout model - observable empty in IE 11

I have a set of input fields that are used to set search params, passed to the controller via knockout and ajax upon pressing the 'search' button.
Each input is bound to a property in a viewModel - each one is a ko.observable().
I have code bound to the keyup event for these fields that will invoke the same search operation when the return key is pressed.
In Chrome, this works fine, but in IE(11) this is never passed!
I have also noted that if I press the tab key to go to the next field, and THEN press return, the search parameter I expect is now populated.
Any ideas? at my wits end...
How do I do the same as pressing the tab key in code, without pressing the tab key?
I think IE's handling of the .change() event in jquery might be different to everyone else...
edited to include sample code - js:
var searchVm = function () {
var self = this;
self.reference = ko.observable("");
self.postCode = ko.observable("");
self.description = ko.observable("");
self.doSearch = function () {
var date = {
Ref: self.reference(),
PostCode: self.postCode(),
Desc: self.description()
};
// do the ajax call to controller
// ... etc ...
}
}
$('.searchField').keyup(function(e) {
if (e.which===13) {
$('#btnSearch').click();
}
});
the page:
<div class='indexRow'>
<label>Reference:</label>
<input type='text' class='searchField' data-bind="value: reference" />
</div>
<div class='indexRow'>
<label>PostCode:</label>
<input type='text' class='searchField' data-bind="value: postCode" />
</div>
<div class='indexRow'>
<label>Description:</label>
<input type='text' class='searchField' data-bind="value: description" />
</div>
<button data-bind='click: doSearch'>Search</button>

Best way to create a reusable Aurelia widget that encapsulates both the label and the edit field

I'm trying to create a simple Aurelia reusable widget that encapsulates both a label and a text input field. The idea is to create a library of these reusable UI widgets to make it easier to compose screens and forms - perhaps taking some learnings from "Angular Formly".
text-field.html template:
<template>
<div class="form-group">
<label for.bind="name">${label}</label>
<input type="text" value.two-way="value" class="form-control" id.one-way="name" placeholder.bind="placeHolder">
</div>
</template>
text-field.js view model:
import {bindable} from 'aurelia-framework';
export class TextField {
#bindable name = '';
#bindable value = '';
#bindable label = '';
#bindable placeHolder = '';
}
client.html template snippet (showing usage of text-field):
<text-field name="firstName" value.two-way="model.firstName" label="First Name" placeHolder="Enter first name"></text-field>
<text-field name="lastName" value.two-way="model.lastName" label="Last Name" placeHolder="Enter last name"></text-field>
client.js view model (showing usage of text-field):
class ClientModel {
firstName = 'Johnny';
lastName = null;
}
export class Client{
heading = 'Edit Client';
model = new ClientModel();
submit(){
alert(`Welcome, ${this.model.firstName}!`);
}
}
QUESTION:
When the final HTML is generated, the attributes are "doubled up" by for example having both the id.one-way="name" AND id="firstName" (see below) - why is this and is there a better way to do this entire reusable text field control?:
<input type="text" value.two-way="value" class="form-control au-target" id.one-way="name" placeholder.bind="placeHolder" id="firstName" placeholder="">
That's normal. Same as if you do style.bind="expression" on a div and expression has display:block. You will end up with <div style.bind="expression" style="display:block"/>. The browser ignores style.bind because it is not a known html attribute. You can just ignore the Aurelia one.