RadDataForm nativescript vue show/hide password - nativescript

Have this part of code form:
<RadDataForm id="loginForm" ref="loginForm" :source="user">
<TKEntityProperty v-tkDataFormProperty name="password" displayName imageResource="res://lock" hintText="Password" index="0">
<TKPropertyEditor v-tkEntityPropertyEditor type="Password">
<TKPropertyEditorStyle v-tkPropertyEditorStyle labelWidth="4" />
</TKPropertyEditor>
</TKEntityProperty>
</RadDataForm>
Need to append icon/image can tap to show/hide password

If I'm not wrong, CustomPropertyEditor is not yet exposed as Vue directive in latest version of nativescript-ui-dataform plugin (as of today v4.0.0).
So you will have to register it first along with RadDataForm, may be something like
import Vue from 'nativescript-vue';
import * as RadDataFormModule from "nativescript-ui-dataform";
import RadDataForm from "nativescript-ui-dataform/vue";
Vue.use(RadDataForm);
Vue.registerElement("TKCustomPropertyEditor", function () {
return RadDataFormModule.CustomPropertyEditor;
});
Now simply use TKCustomPropertyEditor instead of TKPropertyEditor
<TKEntityProperty v-tkDataFormProperty name="password">
<TKCustomPropertyEditor v-tkEntityPropertyEditor
#editorNeedsView="onPasswordEditorNeedsView">
</TKCustomPropertyEditor>
</TKEntityProperty>
Now you can create and assign the view you like on the editorNeedsView event as described in the docs.

Related

Laravel Fortify :: Calling `updatePassword()` function through Livewire

I'm using Livewire to build my Laravel project, and I'm also implementing the security/authentication layer with Fortify.
For various reasons though, I'm not using Jetstream. With that said, there are clearly some very useful features and techniques which Jetstream employs to do its stuff, and so in the true spirit of creativity, I've "borrowed" the following "update-password" form as an example of how Jetstream uses Livewire to interface with Fortify.
This HTML template is a simplified version of the actual HTML code that goes into building my form, but I've taken out all the styling and labelling complexities etc. so that we can focus only on what's important:
<!-- update-password-form.blade.php (Livewire Template) -->
<form wire:submit.prevent="updatePassword">
<input id="current_password" type="password" name="current_password" required="true" />
<input id="password" type="password" name="password" required="true" />
<input id="password_confirmation" type="password" name="password_confirmation" required="true" />
<button type="submit">Change Password</button>
</form>
As we see, Livewire prevents the default submission of the form, and redirects it to the function updatePassword() in the Livewire class. The function as you can see here looks like this:
/**
* Update the user's password.
*
* #param \Laravel\Fortify\Contracts\UpdatesUserPasswords $updater
* #return void
*/
public function updatePassword(UpdatesUserPasswords $updater)
{
$this->resetErrorBag();
$updater->update(Auth::user(), $this->state);
$this->state = [
'current_password' => '',
'password' => '',
'password_confirmation' => '',
];
$this->emit('saved');
}
This all appears to work fine-ish. When I (the user) press [Change Password] Livewire sets the form inactive (to prevent the user from double-submitting the form), and when the response from Laravel/Livewire is received, the form is enabled again. And... well that's it.
The problem is that it doesn't matter what data I submit. If I enter all correct values, the password doesn't update! If I enter incorrect current_password, it doesn't error. If I submit the correct current_password with mismatching password and password_confirmation, I get the same "nothing happened" experience (as an end user). When I check the "network" tab on the browser's dev-tools, I get valid 200 responses each time without any obvious errors being reported in the detail. I know the PHP function is being invoked because if I put a dd($this) style debug in it, the JSON response throws back the Livewire object.
So the question I therefore have is the following...
How does the Fortify framework manage errors, and how am I supposed to catch them (in Livewire) to give the user some useful feedback?
Does the ErrorBag (which is reset in the first line of code) somehow get populated in the $updater->update() function?
Moreover, I copied (sorry, borrowed) this solution from Jetstream project. Does this also mean that the Jetstream interface is equally as unintuitive (from an end-user point of view)? Is there some higher-level concept that I've missed from the Jetstream project?
I was being stupid. The error bag is returned to the view, there just wasn't an outlet in the template to display the response. All I needed was a conditional label (or a span or a div) to display the field if the error exists.
<form wire:submit.prevent="updatePassword">
<input id="current-password" type="password" name="current_password" required="true" />
#error('current_password')
<label id="current-password-err" class="error" for="current-password">{{ $message }}</label>
#enderror
<input id="password" type="password" name="password" required="true" />
#error('password')
<label id="password-err" class="error" for="password">{{ $message }}</label>
#enderror
<input id="password-confirmation" type="password" name="password_confirmation" required="true" />
#error('password_confirmation')
<label id="password-confirmation-err" class="error" for="password-confirmation">{{ $message }}</label>
#enderror
<button type="submit">Change Password</button>
</form>

How to use vee-validate 4 (alpha) with Vuetify for validation?

I am trying to use the latest alpha release of vee-validate. Is it possible to use vee-validate 4 (alpha)'s Form and Field components with Vuetify for validation?
In the example in Vuetify documentation for validation with vee-validate, it only shows use of validation-observer and validation-provider.
Here a good example for veevalidate4, vuejs3 and vuetify3 (typescript,nuxtjs and YUP):
example configuration
in practice
<template>
<div>
<v-app id="inspire">
<v-container fluid fill-height>
<v-row vertical-align="center">
<v-col lg="6" sm="12" align-self="center" offset-lg="3">
<v-card class="elevation-12">
<v-toolbar dark color="success">
<v-toolbar-title>Se connecter</v-toolbar-title>
</v-toolbar>
<v-card-text>
<Form #submit="onSubmit" :validation-schema="schema">
<Field name="username" v-slot="{ field, errors }">
<v-text-field
name="username"
label="Login"
type="email"
v-bind="field"
variant="solo"
append-inner-icon="mdi-magnify"
:error-messages="errors"
></v-text-field>
</Field>
<Field name="password" v-slot="{ field, errors }">
<v-text-field
id="password"
prepend-inner-icon="fa:fas fa-lock"
name="password"
label="Password"
v-bind="field"
type="password"
variant="solo"
:error-messages="errors"
></v-text-field>
</Field>
<v-btn
block
color="success"
size="large"
type="submit"
>
Se connecter
</v-btn>
</Form>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
</template>
<script lang="ts" setup>
const {REST_API_URL} = useRuntimeConfig();
import {Form, Field, ErrorMessage} from "vee-validate";
import * as Yup from "yup";
const schema = Yup.object().shape({
username: Yup.string().required("Email is mandatory.").email("The email
entered doesn’t seem right, please try again."),
password: Yup.string().required("Full name is mandatory."),
});
const props = defineProps({
source: String,
})
function onSubmit(values: any) {
console.log('Submitted with', values);
const {data: token, error, pending} = useFetch(REST_API_URL + '/auth/signin', {method: "POST", body: values})
}
vee-validate v4 does not support Vue 2 at the moment unless Vuetify has also released support for Vue 3 there is no way to use the two at the moment.
Supporting Vue 2 and 3 at the same time is a very hard task for complex libraries such as Vuetify and vee-validate

Why am I getting this warning `No duplicate props allowed react/jsx-no-duplicate-props`

Why am I getting this warning?
warning No duplicate props allowed react/jsx-no-duplicate-props#
It's showing line number 28 but there is nothing props is using.
You probably passed the same prop twice to a Component. e.g.
<MyComponent someProp={'a'} someProp={'b'} />
I also go this error, I was rendering a component and passed 'className' twice. My solution was found here with How to apply multiple classnames to an element. I then just concated the names together, the error went away and my UI rendered perfectly.
//Error
<IconButton
color="secondary"
className={classes.button}
className={classes.test}
component="span"
classes={{
root: classes.checkRoot,
}}
>
//Solution
<IconButton
color="secondary"
className={[classes.button, classes.test ]}
component="span"
classes={{
root: classes.checkRoot,
}}
>
Regarding uppercase/lowercase problems with Material-UI TextField, a component that takes inputProps and InputProps, I didn't want ESLint to output a warning for this, so I added this to my .eslintrc.json file:
"rules": {
"react/jsx-no-duplicate-props": [1, { "ignoreCase": false }]
}
The warning come when any duplicate attribute is used on same tag i.e.
<input id="a" id="b" />
<MyComponent someProp={'a'} someProp={'b'} />
<input placehoder="a" placeholder="a" />
<div className='a' className='b'></div>
It can be as simple as duplicate id on HTML:
<input id="txt-id" id="txtID" />
It can be one of the following:
<input id="a" id="b" />
<MyComponent someProp={'a'} someProp={'b'} />
<input placehoder="a" placeholder="a" />
<div className='a' className='b'></div>
Just wanted to share this since I did not see it as possible errors. But I experience this issue when I had two required on a input.
Example:
<input required type="email" name="form-email" required />
Should be:
<input type="email" name="form-email" required />

react-bootstrap ButtonGroup as radio buttons

I'm trying to make a group of react-bootstrap buttons into a radio button set. I can easily do this with bootstrap with <input type="radio"> elements, but can't figure out how to do this with react-bootstrap. The following code allows the user to select every button, instead of just one.
JS:
const operationButtons = (
<ButtonGroup>
<Button active>Radio 1</Button>
<Button>Radio 2</Button>
</ButtonGroup>
);
React.render(operationButtons, document.getElementById('operationButtonsDiv'));
HTML:
<div name="operationButtonsDiv" id="operationButtonsDiv" data-toggle="buttons"/>
The framework has changed since the accepted answer and they have now replicated the option group behavior of Bootstrap framework. All you need to do now is to add a group name to each option in the group:
<Radio name="groupOptions">Option 1</Radio>
<Radio name="groupOptions">Option 2</Radio>
<Radio name="groupOptions">Option 3</Radio>
So I ended up nesting a radio Input in the Button like you would normally do in Bootstrap.
render() {
return (
<ButtonGroup>
<Button active>Radio 1
<Input ref="input1" type="radio" name="radioButtonSet" value='input1' standalone defaultChecked/>
</Button>
<Button>Radio 2
<Input ref="input2" type="radio" name="radioButtonSet" value='input2' standalone/>
</Button>
</ButtonGroup>
)
}
I also overrode the default .radio css to fix how it's displayed.
.radio {
margin-top: 0;
margin-bottom: 0;
}
React-bootstrap has plans to implement RadioGroup eventually:
https://github.com/react-bootstrap/react-bootstrap/issues/342
Some of the answers on this page don't work. Maybe things have changed since then.
I put together this with the help of React Bootstrap website.
<Col>
<InputGroup>
<InputGroup.Prepend>
<InputGroup.Radio name="group1"/>
<InputGroup.Text >London</InputGroup.Text>
</InputGroup.Prepend>
<FormControl/>
</InputGroup>
<InputGroup>
<InputGroup.Prepend>
<InputGroup.Radio name="group1"/>
<InputGroup.Text >New York</InputGroup.Text>
</InputGroup.Prepend>
<FormControl/>
</InputGroup>
<InputGroup>
<InputGroup.Prepend>
<InputGroup.Radio name="group1"/>
<InputGroup.Text >Colombo</InputGroup.Text>
</InputGroup.Prepend>
<FormControl/>
</InputGroup>
To make the radio button set function as a single group you have to give them a name (so that only one radio button is selected at any given time).
Adding a form control makes the edges of the input nicely rounded off but it also makes the radio button label editable. If this is a problem you can leave out the form control.
If you want a different look and feel you can try this.
<Form.Check
type="radio"
label="London"
name="group2"
id="radio1"
/>
<Form.Check
type="radio"
label="New York"
name="group2"
id="radio2"
/>
<Form.Check
type="radio"
label="Colombo"
name="group2"
id="radio3"
/>
However with these getting the value and handling onChange was difficult. Eventually I used another control.
This is a npm package called react-radio-group. You have to install it by running this line on the command.
npm install react-radio-group
Then import it in your file.
import { Radio, RadioGroup} from 'react-radio-group'
Here's the code for the button group.
<RadioGroup name="fruits" onChange={(e) => handleOnChange(e)}>
<div className="radio-button-background">
<Radio value="Apple" className="radio-button" />Apple
</div>
<div className="radio-button-background">
<Radio value="Orange" className="radio-button" />Orange
</div>
<div className="radio-button-background">
<Radio value="Banana" className="radio-button" />Banana
</div>
</RadioGroup>
classNames are where I have given the styles.
I've just encountered the same problem and solved it by using the the component's state:
_onOptionChange(option) {
this.setState({
option: option
});
}
render() {
render (
<ButtonGroup>
<Button onClick={this._onOptionChange.bind(this, 'optionA')} active={this.state.option === 'optionA'}>Option A</Button>
<Button onClick={this._onOptionChange.bind(this, 'optionB')} active={this.state.option === 'optionB'}>Option B</Button>
</ButtonGroup>
);
}
Just using the tags worked for me. Make sure they all have the same name="radio-group-value-here". To get one of the buttons to be selected on render use checked={bool}. I also used disabled={bool} to show but disallow some choices. I settled on using onClick which seems to be working. Lastly, this is all in a dialog and the offset was needed to keep the radio buttons from smushing up against the left edge.
<Row>
<Col sm={11} smOffset={1} >
<Radio name="changeset-chooser"
checked={this.state.checked === 'current'}
disabled={this.props.changeset.status === "pending"}
onClick={ (e) => { /* event handler */ } } >
Current Data
</Radio>
</Col>
</Row>
<Row>
<Col sm={3} smOffset={1} >
<Radio name="changeset-chooser"
onClick={ (e) => { /* event handler */ } } >
History
</Radio>
</Col>
<Col sm={7} >
<NotPartOfSample />
</Col>
</Row>
This is in 2022, so the library has moved.
Here is how yo would create a yes/no radio:
<Form>
<Form.Check
type="radio"
name="group1"
id={`default-radio`}
label={`Yes!`}
/>
<Form.Check
type="radio"
name="group1"
id={`default-radio`}
label={`No`}
/>
</Form>
The name="group1" makes the buttons TOGGLE. If you don't want to toggle, give them different names or no names.
Hope this helps someone who might stumble across this question like I did.

How to execute code after the jquery.validate validation event?

I am using jquery.validate 1.9 and wish to execute code every time the form automatically validates (using the default behavior).
I hoped there would exist an OnValidated event I could hook into, but can not find one.
After validation executes I wish to conditionally enable other parts of the page if the form is valid, and disable otherwise.
How would one go about adding a method call following the existing validate() function?
I'm using jquery validate 1.8.1, but you should still be able to accomplish this using the valid() function.
valid() will either validate the entire form if you pass it the form ID or individual fields if you pass their respective ID's. It will then return a Boolean based on if they are all valid or not.
Something like this should work:
<script type="text/javascript">
function tab1Validation(){
if($('#field1, #field2, #field3').valid()){
//Logic if all fields valid - eg: $('#NextTab').show();
}else{
//Logic if one or more is invalid
}
}
</script>
<form id="yourform">
<div>
<input type="text" id="field1" name="field1" />
<input type="text" id="field2" name="field2" />
<input type="text" id="field3" name="field3" />
</div>
<input name="nextTab" type="button" value="Next Tab" onClick="tab1Validation();" />
</form>

Resources