I have a component RecipeList and another AddRecipe.after adding a recipe it should be redirected to RecipeList and all items be displayed.
here is the code of AddRecipe Component.
import React ,{Component}from 'react'
import { Mutation } from "react-apollo";
import {ADD_RECIPE} from '../../mutations';
import Error from '../Error';
import {withRouter} from 'react-router-dom';
import {GET_ALL_RECIPIES} from '../../queries'
class AddRecipe extends Component {
...
onSubmit(event,addRecipe){
event.preventDefault();
addRecipe().then(
({data})=>
{
this.props.history.push("/")
}
)
}
render (){
const{name,category,description,instruction,username} = this.state;
return(<div className="App">
<h2>Add recipe</h2>
<Mutation
mutation={ADD_RECIPE}
variables={{name,category,description,instruction,username}}
update={(cache, {data:{addRecipe}}) => {
const {getAllRecipes} = cache.readQuery({ query: GET_ALL_RECIPIES });
cache.writeQuery({
query:GET_ALL_RECIPIES,
data:{getAllRecipes:getAllRecipes.concat[addRecipe]}
})
}} >
{(addRecipe, {data,loading,error})=>
(<form className="form" onSubmit={event=>this.onSubmit(event,addRecipe)}>
<input type="text" name="name" onChange={this.handleChange.bind(this)} placeholder="recipe name" value={name}/>
<select name="category" value="breakfast" id="" onChange={this.handleChange.bind(this)} value={category}>
<option value="breakfast">breakfast</option>
<option value="lunch">lunch</option>
<option value="dinner">dinner</option>
<option value="snack">snack</option>
</select>
<input type="text" name="description" onChange={this.handleChange.bind(this)} placeholder="recipe description" value={description}/>
<textarea name="instruction" id="instruction" cols="30" rows="10" onChange={this.handleChange.bind(this)} value={instruction}> </textarea>
<button type="submit" className="button-primary" disabled = {loading || this.validateForm()}>submit</button>
{error && <Error error={error}/>}
</form>)
}
</Mutation>
</div>)
}
my add recipe mutation is :
import gql from 'graphql-tag';
//RECIPE QUERY
export const GET_ALL_RECIPIES =gql`
query {
getAllRecipes{
name
_id
category
}
}
`
and finally get recipe list query is :
import gql from "graphql-tag";
export const GET_RECIPE_ITEM =gql`
query($id:ID!){
getRecipeItem(_id:$id){
_id
name
category
description
instruction
createdDate
likes
username
}
}`
after submitting form and adding recipe I expect that
first component is redirected to recipe list and
second component the list of recipes includes the newly added recipe .
but I see the old list that does not contain any of newly added recipes and for displaying new components I should refresh the page .
Apollo Client caches data for performance improvements and it does not refetch a list of your recipes because it already in cache.
In order to overcome this, you can either change fetchPolicy from default cache-first to cache-and-network or network-only but I don't recommend this in your case or refetch getAllRecipes query after addRecipe mutation like so:
<Mutation
mutation={ADD_RECIPE}
variables={{name,category,description,instruction,username}}
refetchQueries=['getAllRecipes']
>
...
</Mutation>
Related
<script setup lang="ts">
import * as Vue from 'vue';
import { G, ROLES } from '#/G';
import * as DTO from '#/DTO';
import { FilterMatchMode, FilterOperator } from 'primevue/api'
import { ref, onMounted } from 'vue';
import { RouterLink } from 'vue-router';
const recs = Vue.ref<DTO.IWebPages[]>();
G.doAjaxAsync<DTO.IWebPages[]>('webpages/ForUserAtClient',null).then(o => {
if (o !== null)
recs.value = o;})
const filters = Vue.ref();
const clearFilter = () => {
initFilters();};
const initFilters = () =>
{filters.value = {'global'{value:'',matchMode:FilterMatchMode.CONTAINS },}};
initFilters()
</script>
<template>
<div class="grid">
<div class="col-12 lg:col-12 xl:col-12">
<div class="card mb-0">
<h3>Data Page Menu</h3>
</div>
<br />
<DataTable
:value="recs"
:paginator="true" class="p-datatable-gridlines"
:rows="15" dataKey=""
:rowHover="true"responsiveLayout="scroll"paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
:alwaysShowPaginator="false"currentPageReportTemplate="Showing {first} to {last} of {totalRecords}"
v-model:filters="filters" filterDisplay="menu" :globalFilterFields="['company']">
<template #empty>
No records
</template>
<Column field="company" header="Company" />
<Column field="dataType" header="Type" />
<Column field="screenText" header="Text" class="p-link" />
<template>
Above is my code which displays data in three columns. The last row screenText has text values for example NewAssignent. I want to make that text a router link to another page called NewAssignment. The tags and are PrimeVue tags. Wrappers over html table, row and column tags. If you see the third column I placed a class="p-link" but it makes the whole cell clickable. I want the text to be recognized as there are different pages and they should link to these values inside column cell. The other cell value is search so it will go to search page. The data coming from the API for the third column should be links to other pages.
I have a input box and user have to give their facebook user id on that so i make input box with default value https://www.facebook.com and then user give their user-profile-link then it will update data but i got this error when anything gonna type on input box
<div class="column">
<label class="label">Facebook Id::</label>
<input class="input is-medium" type="text" v-model="'https://www.facebook.com/'+data.fblink">
</div>
<script>
import contactInfo from './ContactInfo'
export default {
components: {contactInfo},
props: ['data'],
binding is for variables only, use this it works
<div class="column">
<label class="label">Facebook Id::</label>
<input class="input is-medium" type="text" v-model="facebook_link">
</div>
in your data variable add facebook_link as string. then if you want to update use this
'https://www.facebook.com/'+facebook_variable
v-model needs a variable to bind to, not a fixed string.
...
<input v-model="fbProfileLink"/>
...
export default {
components: {contactInfo},
props: ['data'],
data() {
return {
fbProfileLink: 'https://www.facebook.com/'
}
}
}
If you're making any requests to that link though, you probably shouldn't let the user manipulate it freely but put guards in place so you won't be making requests to a user provided URL blindly.
I'm working with a template form component with angular2 and I cannot get to set the focus in my firstName input element after submit the form. The form is reseted fine but no way of setting focus.
This is my component code:
export class TemplateFormComponent {
#ViewChild('f') form: any;
onSubmit() {
if (this.form.valid) {
console.log("Form Submitted!");
this.form.reset();
this.form.controls.firstName.focus();
}
}
}
and my template code:
<form novalidate autocomplete="off" #f="ngForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label>First Name</label>
<input type="text"
class="form-control"
name="firstName"
[(ngModel)]="model.firstName"
required
#firstName="ngModel">
</div>
</form>
On your view, set a reference to the input field you want to focus (you already have that with #firstName).
Then, on your component code, create an access to it with #ViewChild:
#ViewChild('firstName') firstNameRef: ElementRef;
And finally, right after reseting the form:
this.firstNameRef.nativeElement.focus()
ps.: I would expect the FormControl api to expose a focus method, but this issue on gitHub suggests it may never happen.
For a more generic solution see
Is it possible to get native element for formControl?
`
#Directive({
selector: '[ngModel]',
})
export class NativeElementInjectorDirective {
constructor(private el: ElementRef, private control : NgControl) {
(<any>control.control).nativeElement = el.nativeElement;
}
}
`
This will add the nativeElement to EACH form control once you add the directive to your module.
UPDATE: a much simpler solution for this usecase
To set focus on the first invalid element on a form create a directive like this:
import { Directive, HostListener, ElementRef} from '#angular/core';
#Directive({
selector: '[focusFirstInvalidField]'
})
export class FocusFirstInvalidFieldDirective {
constructor(private el: ElementRef) { }
#HostListener('submit')
onFormSubmit() {
const invalidElements = this.el.nativeElement.querySelectorAll('.ng-invalid');
if (invalidElements.length > 0) {
invalidElements[0].focus();
}
}
}
Then simply add it to your form element tag
Simple solution: add "autofocus" to your input element properties.
<input type="text" class="form-control" name="firstName" autofocus required>
I am using Angular2 and when users go to my page using IE11 on Windows 7 (which appears to be the only combination that has issues) they cannot enter information into the textboxes/textareas. The drop-downs work just fine as do the checkboxes (which will show/hide additional fields as needed although you still cannot enter information into the new text fields).
If the user clicks the submit button all the required fields show as needing input and then the user can enter the information.
If it matters, the users are redirected to this page after enter RECAPTCHA information. If I take out the "canActivate" from my app routing module it works.
Here is the captcha code
import { Component } from '#angular/core';
import {
Router,
NavigationExtras
} from '#angular/router';
import { CaptchaService } from '../../utils/captchaguard/captcha.service';
import { ReCaptchaComponent } from 'angular2-recaptcha/lib/captcha.component';
#Component({
moduleId: module.id,
templateUrl: 'captcha.component.html'
})
export class CaptchaComponent {
message: string;
constructor(
public captchaService: CaptchaService,
public router: Router) {
//this.captchaService.isLoggedIn = true; //Uncomment out for testing
this.captchaService.isLoggedIn = false; //Uncomment out for live
}
handleCorrectCaptcha(userResponseKey: any) {
let redirect = this.captchaService.redirectUrl ? this.captchaService.redirectUrl : '/admin';
let redirectParts = redirect.split('/');
let appendID = redirect[redirect.length - 1];
//let appendID = 0;
this.captchaService.isLoggedIn = true;
//this.router.navigate(['/studyfd' + appendID]);
this.router.navigateByUrl('/studyfd' + appendID);
//this.router.navigate(['/studytest/0']);
}
}
Here is a portion of the HTML that generates the page in question:
<!-- First and Last Name -->
<div class="row">
<div class="col-sm-6">
First Name, Last Name
</div>
<div class="col-sm-3">
<input type="text" name="FirstName" id="firstname" required="required"
placeholder="First Name" class="required "
[(ngModel)]="user.FirstName" *ngIf="!readonly" />
<label *ngIf="readonly">{{user.FirstName}}</label>
</div>
<div class="col-sm-3">
<input type="text" name="LastName" id="lastName" required="required"
placeholder="Last Name" [(ngModel)]="user.LastName" *ngIf="!readonly"
class="required " />
<label *ngIf="readonly">{{user.LastName}}</label>
</div>
</div>
Turns out the issue was due to the RECAPTCHA window not closing (probably because of the redirect I was doing in handleCorrectCaptcha). Resolved by adding a hidden button and in the handleCorrectCaptcha method I made the button visible. Clicking on the button performed the redirect that was originally done in the handleCorrectCaptcha method.
I am building a Ionic 2 (typescript) application. Having problem ONLY in a simple model-driven form validation in checkbox (ion-checkbox tag).
I'm using FormBuilder to build the form module. I want the form to be validated / not validated based on the checked state of a checkbox input control. But its working one-way only. Here's my code :
reg.html
<ion-content padding>
<form class="client_profile" [formGroup]="regForm">
<div class="profile_pic" id="profile_pix">
<img src="build/images/home.svg" id="client_camera_pic" />
</div>
<ion-item>
<ion-label floating>What we would call you?</ion-label>
<ion-input type="text" formControlName="client_name"></ion-input>
</ion-item>
<ion-item>
<ion-label floating>Choose your username</ion-label>
<ion-input type="text" name="client_username" value="" #client_username formControlName="client_username"></ion-input>
</ion-item>
<ion-item>
<ion-label floating>Where we will drop your Email?</ion-label>
<ion-input type="email" name="client_email" value="" #client_email formControlName="client_email"></ion-input>
</ion-item>
<ion-item>
<ion-label floating>We also need your phone number</ion-label>
<ion-input type="number" name="client_phone" value="" #client_phone formControlName="client_phone"></ion-input>
</ion-item>
<ion-item class="reg_terms">
<ion-checkbox secondary #terms name="terms" value="" checked="false" formControlName="terms"></ion-checkbox>
<ion-label>I accept the Terms & Conditions</ion-label>
</ion-item>
</form>
<div>
<ion-buttons right class="client_reg_done">
<button danger class="reg_complete" (click)="process_client_reg()" [disabled]="!regForm.valid">NEXT</button>
</ion-buttons>
</div>
</ion-content>
reg.ts
import { Component, ViewChild, ElementRef } from '#angular/core';
import { FORM_PROVIDERS, FormBuilder, FormControl, FormGroup, AbstractControl, Validators, REACTIVE_FORM_DIRECTIVES } from '#angular/forms';
import { App, NavController, ViewController, ModalController, LoadingController, LoadingOptions } from 'ionic-angular';
#Component({
templateUrl: "build/pages/registration/reg.html"
})
export class Registration {
ngAfterViewInit(){
}
regForm: FormGroup;
constructor(public app: App, public nav: NavController, public viewCtrl: ViewController, public elem: ElementRef, public modalCtrl: ModalController, public loading: LoadingController, public fb: FormBuilder){
}
ngOnInit() {
this.regForm = this.fb.group({
client_name: ['', Validators.compose([Validators.required, Validators.maxLength(30), Validators.pattern('^[a-zA-Z\. ]+$')])],
client_username: ['', Validators.compose([Validators.required, Validators.maxLength(20), Validators.pattern('[a-zA-Z0-9-_\.]+')])],
client_email: ['', Validators.compose([Validators.required, Validators.pattern('^[a-zA-Z0-9-_]+#[a-zA-Z]+\.[a-zA-Z]{2,4}$')])],
client_phone: ['', Validators.compose([Validators.required, Validators.pattern('^[\+0-9]{10,12}$')])],
terms: [null, Validators.required]
});
}
}
Actual view:
Checking / unchecking the Terms & Condition checkbox doesn't updating the validation logic and the 'NEXT' button disabled state is not updating. Its because form validation isn't taking account this checkbox. Some help is appreciated.
Initialising your terms control with null seems to break the emission of change events. Try adding this subscription:
this.regForm.valueChanges.subscribe(v => {
console.log('Required validation failed: ' + this.form.controls['terms'].hasError('required'));
console.log('Required validation touched: ' + this.form.controls['terms'].touched);
console.log('Required validation status: ' + this.form.controls['terms'].status);
});
Toggling the terms checkbox doesn't result in any logging. This might be a bug.
Now change your control to be initialised as false and try again: terms: [false, Validators.required] This time the logging happens and you can see what's going on.
Unfortunately, now the control is in the valid state as soon as it loads. You can check that with similar logging after building your FormGroup. The best solution would be to create an is-true custom validator, but a quick and dirty solution would be to change your button:
[disabled]="!regForm.valid || !form.controls.terms.touched"