How to disable autofill on ember form field - javascript

I have a form for updating the details of alumni in ember using RESTful api. Is it possible to prevent the form from auto filling the data I previously entered in the form corresponding to another record in the model?
I have these codes in my update route directory(I am using pod-structure):
controller.js
# app/alumnis/update/controller.js
import Controller from '#ember/controller';
import { get, set } from '#ember/object';
export default Controller.extend({
firstName: null,
actions: {
updateAlumni(value) {
let firstName = get(this, 'firstName');
if(firstName) {
firstName = firstName.charAt(0).toUpperCase() + firstName.slice(1).toLowerCase();
this.get('store').findRecord('alumni', value).then(function(alumni) {
alumni.set('firstName', firstName);
alumni.save();
});
}
this.transitionToRoute('alumnis.show', value)
},
},
});
route.js
# app/alumnis/update/route.js
import Route from '#ember/routing/route';
import { set } from '#ember/object';
export default Route.extend({
model(params) {
return this.store.findRecord('alumni', params.id);
},
setupController(controller, model) {
set(controller, 'alumni', model);
}
});
template.hbs
# app/alumnis/update/template.hbs
<form class="alumniForm" {{action "updateAlumni" on="submit"}}>
<div class="form-group">
<h3>First Name : {{input name="firstName" type="text" value=firstName placeholder=alumni.firstName autocomplete="off"}}</h3>
</div>
<button class="btn btn-primary" {{action "updateAlumni" alumni.id}}>Submit</button>
</form>
router.js
# app/router.js
import EmberRouter from '#ember/routing/router';
import config from './config/environment';
const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route('alumnis', function() {
this.route('show', {path: '/:id'});
this.route('add', {path: '/add'});
this.route('update', {path: '/:id/update'});
});
});
export default Router;
On the first rendering of update route after every reloading, no form fields are filled automatically. But, once we enter data to the firstName input field, it is rendered to form field in update page of any other record in the model alumni.

Properties that are set in a controller in ember will remain set when you re-navigate to the page.
The logic you've shown, leads me to believe you don't even need the controller. You are modifying a model property, saving it and transitioning.
You were doing a round-about way of updating the record, The alumni record was your model, yet you were trying to re-fetch it from the store.
route.js
# app/alumnis/update/route.js
import Route from '#ember/routing/route';
import { set,get } from '#ember/object';
export default Route.extend({
model(params) {
return this.store.findRecord('alumni', params.id);
},
updateAlumni() {
let changedAttrs = get(this, 'model').changedAttributes();
if (changedAttrs.firstName) {
let firstName = get(this, 'model.firstName').toLowerCase().capitalize();
set('model.firstName', firstName);
}
get(this,'model').save()
this.transitionToRoute('alumnis.show', get(this,'model'))
}
});
template.hbs
# app/alumnis/update/template.hbs
<form class="alumniForm" {{action "updateAlumni" on="submit"}}>
<div class="form-group">
<h3>First Name : {{input name="firstName" type="text" value=model.firstName placeholder=alumni.firstName autocomplete="off"}}</h3>
</div>
<button class="btn btn-primary" {{action "updateAlumni"}}>Submit</button>
</form>

I was able to resolve the issue by changing the below codes:
controller.js
# app/alumnis/update/controller.js
import Controller from '#ember/controller';
import { get, set } from '#ember/object';
export default Controller.extend({
firstName: null,
actions: {
updateAlumni(value) {
let alumni = get(this, 'alumni');
let changedAttrs = alumni.changedAttributes();
if(changedAttrs.firstName) {
let firstName = alumni.firstName.toLowerCase().capitalize();
alumni.set('firstName', firstName);
alumni.save()
}
this.transitionToRoute('alumnis.show', value)
},
},
});
template.hbs
# app/alumnis/update/template.hbs
<form class="alumniForm" autocomplete="off" {{action "updateAlumni" on="submit"}}>
<div class="form-group">
<h3>First Name : {{input name="firstName" type="text" value=alumni.firstName}}</h3>
</div>
<button class="btn btn-primary" {{action "updateAlumni" alumni.id}}>Submit</button>
</form>
No change in app/alumnis/update/route.js

Related

Ember Octane Upgrade How to pass values from component to controller

Upgrade from Ember <3.15 to >=3.15. How do I pass form values from a controller into a component?
I cannot begin to explain the number of diagnostic combinations attempted and their corresponding errors received. So, I figure it best to ask how it should be done correctly? Is Glimmer involved?
A simple example: pass a change password from old password to both a new and confirm password via a component to a controller. In the Component, I keep getting onsubmit() is not a function error.
Code example:
User Input Form
ChangePasswordForm.hbs
<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<h3>Change Password</h3>
<form class="m-t" role="form" {{on "submit" this.changePassword}}>
{{#each errors as |error|}}
<div class="error-alert">{{error.detail}}</div>
{{/each}}
<div class="form-group">
{{input type="password" class="form-control" placeholder="Old Password" value=oldPassword required="true"}}
</div>
<div class="form-group">
{{input type="password" class="form-control" placeholder="New Password" value=newPassword required="true"}}
</div>
<div class="form-group">
{{input type="password" class="form-control" placeholder="Confirm Password" value=confirmPassword required="true"}}
</div>
<div>
<button type="submit" class="btn btn-primary block full-width m-b">Submit</button>
</div>
</form>
</div>
</div>
Template Component
ChangePassword.hbs
<Clients::ChangePasswordForm #chgpwd={{this.model}} {{on "submit" this.changePassword}} #errors={{this.errors}} />
Component
ChangePasswordForm.js
import Component from '#glimmer/component';
import { tracked } from '#glimmer/tracking';
import { action } from '#ember/object';
export default class ChangePasswordForm extends Component {
#tracked oldPassword;
#tracked newPassword;
#tracked confirmPassword;
#tracked errors = [];
#action
changePassword(ev) {
// Prevent the form's default action.
ev.preventDefault();
this.oldPassword = ev.oldPassword;
this.newPassword = ev.newPassword;
this.confirmPassword = ev.confirmPassword;
// Call the form's onsubmit method and pass in the component's values.
this.onsubmit({
oldPassword: this.oldPassword,
newPassword: this.newPassword,
confirmPassword: this.confirmPassword
});
}
}
Controller
ChangePassword.js
import Controller from '#ember/controller';
import { inject as service } from '#ember/service';
import { action } from '#ember/object';
export default class ChangePassword extends Controller {
#service ajax
#service session
#action
changePassword(attrs) {
if(attrs.newPassword == attrs.oldPassword)
{
this.set('errors', [{
detail: "The old password and new password are the same. The password was not changed.",
status: 1003,
title: 'Change Password Failed'
}]);
}
else if(attrs.newPassword != attrs.confirmPassword)
{
this.set('errors', [{
detail: "The new password and confirm password must be the same value. The password was not changed.",
status: 1003,
title: 'Change Password Failed'
}]);
}
else
{
let token = this.get('session.data.authenticated.token');
this.ajax.request(this.store.adapterFor('application').get('host') + "/clients/change-password", {
method: 'POST',
data: JSON.stringify({
data: {
attributes: {
"old-password" : attrs.oldPassword,
"new-password" : attrs.newPassword,
"confirm-password" : attrs.confirmPassword
},
type: 'change-passwords'
}
}),
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/vnd.api+json',
'Accept': 'application/vnd.api+json'
}
})
.then(() => {
// Transistion to the change-password-success route.
this.transitionToRoute('clients.change-password-success');
})
.catch((ex) => {
// Set the errors property to the errors held in the ex.payload.errors. This will allow the errors to be shown in the UI.
this.set('errors', ex.payload.errors);
});
}
}
}
Model
ChangePassword.js
import Route from '#ember/routing/route';
import AbcAuthenticatedRouteMixin from '../../mixins/abc-authenticated-route-mixin';
export default Route.extend(AbcAuthenticatedRouteMixin, {
//export default class ChangePasswordRoute extends Route(AbcAuthenticatedRouteMixin, {
model() {
return {
oldPassword: '',
newPassword: '',
confirmPassword: ''
};
},
})
There is no onsubmit method in #glimmer/component, so you cannot call this.onsubmit inside an action in the component.
First, you need to pass the action created in your controller to your component. This can be done like this:
<ChangePasswordForm #chgpwd={{this.model}} #changePassword={{action 'changePassword'}} />
Remember, you cannot pass data up any more in a glimmer component, you need to use an action since everything is one way binding.
Second, you need to call this action inside your glimmer component:
this.args.changePassword({
oldPassword: this.oldPassword,
newPassword: this.newPassword,
confirmPassword: this.confirmPassword
});
I've created an Ember Twiddle for you to show this example working.

Multiple forms with one submit() method by Vue

I have a few forms. Every of them have the same logic (validation, sending...) so, I want to create one method to control actions on my forms. For now my code is redundancy, because I have the same methods onSubmit() on every .vue file.
my HTML:
<div id="app">
<myform-one></myform-one>
<myform-two></myform-two>
</div>
my JavaScript (main.js - entry file in webpack):
import Vue from 'vue';
import Myform1 from './myform1.vue';
import Myform2 from './myform2.vue';
new Vue({
el: '#app',
components: {
myformOne: Myform1,
myformTwo: Myform2
}
});
and VUE components files:
myform1.vue:
<template>
<div>
<form #submit.prevent="onSubmit">
<input type="text" v-model="fields.fname11" />
<input type="text" v-model="fields.fname12" />
<button type="submit">submit</button>
</form>
</div>
</template>
<script>
let formfields = {
fname11: '',
fname12: ''
};
export default {
data() {
return {
fields: formfields
}
},
methods: {
onSubmit() {
// code responsible for reading, validating and sending data here
// ...
console.log(this.fields);
}
},
}
</script>
and myform2.vue:
<template>
<div>
<form #submit.prevent="onSubmit">
<input type="text" v-model="fields.fname21" />
<input type="text" v-model="fields.fname22" />
<input type="text" v-model="fields.fname23" />
<button type="submit">submit</button>
</form>
</div>
</template>
<script>
let formfields = {
fname21: '',
fname22: '',
fname23: '',
};
export default {
data() {
return {
fields: formfields
}
},
methods: {
onSubmit() {
// code responsible for reading, validating and sending data here
// ...
console.log(this.fields);
}
},
}
</script>
How can I create and use one, common method submitForm()? And where its code should be (good practice)?
Create a separate file which contains the logic:
// submitForm.js
export default function (fields) {
// code responsible for reading, validating and sending data here
// ...
}
Then use that logic inside the components
import submitForm from "../services/submitForm.js"
...
methods: {
onSubmit() {
submitForm(this.fields)
}
}
Vue3 (with Quasar for me but I'm sure it would work for any framework):
Say you have a parent which contains a number of forms <Forms />:
First create a composable function like so useForms.js:
import { ref } from 'vue'
const forms = ref([])
export function useForms(){
const checkForms = () => {
forms.value.forEach((form) => form.validate()
}
const addFormToFormsArray = (form) => {
forms.value.push(form)
}
return { forms, addFormToFormsArray, checkForms }
}
Then import it into <Forms />:
<template>
<Form />
<Form />
<Form />
<button #click="checkForms">Check Form</button>
</template>
<script setup>
import { useForms } from '../useForms';
const { checkForms } = useForms()
</script>
Finally, inside the <Form />:
<template>
<form ref="form">
.../stuff
</form>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useForms } from '../useForms';
const form = ref(null)
onMounted(() => {
addFormToFormsArray(form.value)
})
const { checkForms, addFormToFormsArray } = useForms()
</script>
When performing the check function in the parent, it should go through each form and check for any issues.
There are some options. My favorite is creating a mixin vue docs mixins
export const form_functionality = {
methods: {
on_submit() {
//logic of submit
},
//here we can have other reusable methods
}
}
Then in your components use that mixin as follow:
import { form_functionality } from 'path_of_mixin'
export default {
mixins: [form_functionality]
}
In the end, what mixins has (created, methods, data etc) will be merged to the component
which uses that mixin.
So, practically you can access the mixin method like this.on_submit()

How do I increment field in Database for each entry on Vue.js

I have a Vue app which has a form which you can submit and all the submissions are shown on a different page with the option to delete them or give each a thumbs up. The issue I am having is targeting each entries thumbsUp to increment it by one. For example, I have a function "thumbsUp" which returns
return this.forms.form[1].thumbsUp++ on each click, but I would like it to target each entry automatically.
Forum submission:
<script>
import {formRef} from '../firebase' //imports reference to form object stored in firebase
export default {
data(){
return{
submitted:false,
form:{
name:'',
state:'',
review:'',
thumbsUp: 0
},
name:'hey',
}
},
methods: {
//pushes this.form object as {form} to firebase using the formRef
submitForm(){
formRef.push({form: this.form, edit: false})
this.submitted = true
}
}
}
</script>
Forum review page:
<template lang="html">
<div class="" class="wrapper">
<div v-for="review of forms" class="reviews">
{{review.name}}
<h1><strong>{{review.form.name}}</strong>, from <strong>{{review.form.state}}</strong> said: </h1>
<p>{{review.form.review}}</p>
<button #click="removePost(review['.key']) "type="button" name="button">Remove Post</button>
<span >Thumbs up: {{review.form.thumbsUp}} </span>
<button #click="thumbsUp" type="button" name="button">Thumbs up!</button>
</div>
</div>
</template>
<script>
import {formRef} from '../firebase'
export default {
data(){
return{
}
},
firebase:{
forms: formRef //stores form reference inside of "forms"
},
methods:{
//takes key from child of formRef to remove post
removePost(key){
formRef.child(key).remove()
},
thumbsUp(){
return this.forms.form[1].thumbsUp++ //needs fix
}
},
}
On the button click function, pass the form element that you loop through. In your case, thumbsUp(review.form).
Then in your thumbsUp function,
thumbsUp(form) {
form.thumbsUp +=1;
}

Ember model data not showing up in template

I am building my first ember application and I can't get the model data to go from my songs modal to my songs template...
router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('songs');
this.route('song', {path: 'songs/:song_trackId'});
});
export default Router;
Here is my songs.js which displays properly
<div>songs</div>
{{#each model as |song|}}
{{#link-to 'song' song}}
<img height='100px' width='100px' src = '{{song.artworkUrl100}}'>
<div>{{song.trackId}}</div>
{{/link-to}}
{{/each}}
{{outlet}}
Here is my songs route..
import Ember from 'ember';
var data = {
"results" : [
{"wrapperType":"track", "kind":"song", "artistId":148662, "collectionId":528436018, "trackId":528437613,......
.
.
.
]}
export default Ember.Route.extend({
model: function(){
return data.results;
}
});
Lastly...the song template where the data should go when the user clicks
<div>HI</div>
<div> ArtistId: {{artistId}} </div>
<div> trackId: {{trackId}} </div>
<div> Kind: {{kind}} </div>
{{outlet}}
I dont think the link-to is setup improperly. Am I referencing the dynamic song incorrectly in the router?
I didn't define a song route model....
All I needed to do is set up a model in the song route as follows..
I left out the data object but in general I had to pass in the param and then grab it with the model here to find the object I was looking for with a filter
export default Ember.Route.extend({
model: function(params) {
var index = data.results.filter(function(obj){
return obj.trackId == params.song_trackId
})
var values = index[0]
return values
}
});

ember simple auth save user profile in a session

I can't find out why the method set of session this.get('session').set('name', name); does not persist after having reloaded the page. I followed exactly what was mentioned here.
My code
//controllers/authentification.js
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service('session'),
actions: {
authenticate() {
var this2 = this;
let {
email, motDePasse
} = this.getProperties('email', 'motDePasse');
this.get('session').authenticate('authenticator:oauth2', email, motDePasse).then(function () {
this2.store.queryRecord('membre', {
membre: {
email: email
}
}).then(function (membre) {
var nom = membre.get('nom');
this2.get('session').set('nom', nom);
console.log('name:', nom);
});
}).catch((reason) => {
this.set('errorMessage', reason.error || reason);
});
}
}
});
for the session-store/sessions.js
import Cookie from 'ember-simple-auth/session-stores/cookie';
export default Cookie.extend();
controllers/application.js
import Ember from 'ember';
import SessionService from 'ember-simple-auth/services/session';
export default Ember.Controller.extend({
session: Ember.inject.service('session'),
index: function () {
this.transitionTo('index');
}
});
template/application.js
<ul class="nav navbar-nav navbar-right">
{{#if session.isAuthenticated}}
<li>nom :{{session.nom}}</li>
<li><a {{action 'logout' on="click"}}>Deconnecter</a></li>
{{else}}
{{#link-to 'authentification' tagName="li"}}<a href>Authentification</a>{{/link-to}}
{{/if}}
</ul>
the first time i authenticate, the variable "nom" appears but once i reload the page, the variable "nom" disappears but the session stille isAuthenticated
i have found the solution , i have just to use
this2.get('session').set('.data.nom', nom);
instead of
this2.get('session').set('nom', nom);

Categories