i have been wracking my brain for hours on end with no success. My Graphql Mutation for a form isn't working but my Graphql queries are working fine. Any idea why with the below code? I'm using supabase as my database, postgraphile for graphql, nuxtjs for the ui
<template>
<div>
<form method="POST" #submit.prevent="createAgreement()">
<nav class="navbar navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand">
<input type="reset" class="btn btn-warning" value="Reset"></a>
<a class="navbar-brand">
<input type="submit" class="btn btn-warning" value="Save Agreement"></a>
</div>
</nav>
<br>
<div class="row">
<div class="col-3">
<!-- Tab navs -->
<div id="v-tabs-tab" class="nav flex-column nav-tabs text-center" role="tablist" aria-orientation="vertical">
<a id="v-tabs-home-tab" class="nav-link active" data-mdb-toggle="tab" href="#v-tabs-home" role="tab"
aria-controls="v-tabs-home" aria-selected="true">Create A New Agreement</a>
</div>
<!-- Tab navs -->
</div>
<div class="col-9">
<div id="v-tabs-tabContent" class="tab-scope">
<div id="v-tabs-home" class="tab-pane fade show active" role="tabpanel" aria-labelledby="v-tabs-home-tab">
<div class="table table-responsive">
<table class="table">
<tbody>
<tr>
<td style="text-align: right;">Agreement Name</td>
<td>
<input v-model="name" type="text" required />
</td>
</tr>
<tr>
<td style="text-align: right;">Agreement Type</td>
<td>
<input v-model="type" type="text" name="Type" />
</td>
</tr>
</tbody>
</table>
</div>
<br><br>
<div id="accordionExample" class="accordion">
<div class="accordion-item">
<h2 id="headingOne" class="accordion-header">
<button class="accordion-button" type="button" data-mdb-toggle="collapse"
data-mdb-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
Content
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne"
data-mdb-parent="#accordionExample">
<div class="accordion-body">
<div class="table table-responsive">
<table class="table">
<tbody>
<tr>
<td style="text-align: right;">Excerpt</td>
<td>
<textarea id="excerpt" v-model="excerpt" type="textarea" cols="50" rows="10"
value="Add a short Description"></textarea>
</td>
</tr>
<tr>
<td style="text-align: right;">Description</td>
<td>
<textarea id="excerpt" v-model="content" type="textarea" cols="50" rows="10"
value="Add a Description"></textarea>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 id="headingThree" class="accordion-header">
<button class="accordion-button" type="button" data-mdb-toggle="collapse"
data-mdb-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
Images and Videos
</button>
</h2>
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree"
data-mdb-parent="#accordionExample">
<div class="accordion-body">
<td>
<input v-model="image" type="image" name="headshot" value="Select an image to upload"
help="Select a png, jpg or gif to upload." validation="mime:image/jpeg,image/png,image/gif" />
</td>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</template>
<script>
import gql from "graphql-tag";
import allAgreementsList from "~/apollo/queries/sales/agreements";
const ADD_AGREEMENTS = gql`
mutation ($name:String!,$excerpt:String,$type:String,$content:String,$image:String){
createAgreement(objects: {name: $name, excerpt: $excerpt, type: $type, content: $content, image: $image}) {
affected_rows
returning {
name
excerpt
type
content
image
}
}
}`;
export default {
data() {
return {
type: [],
name: " ",
excerpt: " ",
content: " ",
image: " ",
}
},
head: {
title: 'Add New Agreement'
},
methods: {
async addAgreement() {
const name = this.name;
const content = this.content;
const excerpt = this.excerpt;
const type = this.type;
const image = this.image;
await this.$apollo.mutate({
mutation: ADD_AGREEMENTS,
variables: {
name,
excerpt,
type,
content,
image,
},
update: (cache, { data: { insertAgreements }}) => {
// Read data from cache for this query
try {
const insertedAgreement = insertAgreements.returning;
console.log(insertedAgreement)
cache.writeQuery({
query: allAgreementsList
})
}
catch (err) {
console.error(err)
}
}
}).then(() => {
this.$router.push({path: '../sales/agreements'})
}).catch(err => console.log(err));
this.name = ' ';
this.excerpt = ' ';
this.type = ' ';
this.content = ' ';
this.image = ' ';
},
}
}
</script>
Also to note I have complete permissions on my database
So i switched systems and ended up using Apollo-Server, Prisma (my ORM), and Typegraphql just in case anyone wants a working solution with this combination:
import "reflect-metadata";
import { buildSchema } from "type-graphql";
import { ApolloServer } from "apollo-server";
import * as path from "path";
import { PrismaClient } from "#prisma/client";
import { resolvers } from "../prisma/generated/type-graphql";
interface Context {
prisma: PrismaClient;
}
async function main() {
const schema = await buildSchema({
resolvers,
emitSchemaFile: path.resolve(__dirname, "./generated-schema.graphql"),
validate: false,
});
const prisma = new PrismaClient();
await prisma.$connect();
const server = new ApolloServer({
schema,
context: (): Context => ({ prisma }),
});
const { port } = await server.listen(8001);
console.log(`GraphQL is listening on ${port}!`);
}
main().catch(console.error);
It also turned out to be a cors issue.
Related
I am developing a web page. there i am using v-modal with vuejs. I am making an object form new Form. it gets. in the html it inserts the id which is input by user but i want to replace that with the userID gotten from the currently logged in user. i tried getter and settter in the script but it does not change the form.id. it takes the input from user . the following is my code. sorry for the messy code.
<template>
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0">Applications Page</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><router-link to="/dashboard">Home</router-link></li>
<li class="breadcrumb-item active">About Page</li>
</ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Application</h3>
<div class="card-tools">
<button class="btn btn-success" #click="newModal">Add New
<i class="fa-regular fa-calendar-plus fa-fw"></i>
</button>
</div>
</div>
<div class="card-body table-responsive p-0">
<table class="table table-hover text-nowrap">
<thead>
<tr>
<th>ID</th>
<th>User_ID</th>
<!-- <th>body</th> -->
<!-- <th>category_id</th> -->
<!-- <th>user_id</th> -->
<th>Job_ID</th>
<th>Status</th>
<!-- <th>image</th> -->
<th>Modify</th>
</tr>
</thead>
<tbody>
<tr v-for="application in applications.data" :key="application.id">
<td> {{ application.id }}</td>
<td>{{ application.user_id }}</td>
<td>{{ application.job_id }}</td>
<td> {{ application.status }}</td>
<td>
<a href="#" #click="editModal(application)">
<i class="fa fa-edit blue"></i>
</a> /
<a href="#" #click="deleteApplication(application.id)">
<i class="fa fa-trash red"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" v-show="!editmode" id="myModalLabel">Add New Application</h1>
<h1 class="modal-title fs-5" v-show="editmode" id="myModalLabel">Udate Application</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form #submit.prevent="editmode ? updateApplication() : createApplication() ">
<div class="modal-body">
<div class="form-group">
<input v-model="form.user_id" type="text" name="user_id" placeholder="user_id"
class="form-control" :class="{ 'is-invalid': form.errors.has('user_id') }">
<has-error :form="form" field="user_id"></has-error>
</div>
<!-- <input :value="userID" > -->
<!-- <div class="form-group"></div> -->
<!-- <select v-model="form.user_id">
<option :value=userID.id></option>
</select>
</div> -->
<!-- <input v-model="form.user_id" type="text" name="user_id" placeholder="user_id"
class="form-control" :class="{ 'is-invalid': form.errors.has('user_id') }"> <has-error :form="form" field="user_id"></has-error> -->
<div class="form-group">
<textarea v-model="form.job_id" type="text" name="job_id" placeholder="job_id"
class="form-control" :class="{ 'is-invalid': form.errors.has('job_id') }"></textarea>
<has-error :form="form" field="job_id"></has-error>
</div>
<div class="form-group">
<input v-model="form.status" type="text" name="status" placeholder="status"
class="form-control" :class="{ 'is-invalid': form.errors.has('status') }">
<has-error :form="form" field="status"></has-error>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">Close</button>
<!-- <button type="submit" class="btn btn-primary" data-bs-dismiss="modal">Create</button> -->
<button v-show="editmode" type="submit" class="btn btn-success">Update</button>
<button v-show="!editmode" type="submit" class="btn btn-primary">Create</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
import Form from 'vform';
import Swal from 'sweetalert2/dist/sweetalert2.js';
import 'sweetalert2/src/sweetalert2.scss';
export default {
data: () => ({
editmode: false,
applications: {},
// catIDs: {},
userID: {},
form: new Form({
id: '',
user_id: '',
job_id: '',
status: '',
// get newUserID (){
// return this.user_id;
// },
// set newUserID(newUser_id){
// this.user_id = newUser_id[0];
// }
})
}),
methods: {
updateApplication(id) {
this.form.put('api/application/' + this.form.id)
.then(() => {
$('#myModal').modal('hide');
Swal.fire('Application updated!');
// this.$emit('afterCreate');
this.loadApplication();
})
.catch(() => {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: 'Something went wrong!',
})
});
},
newModal() {
this.editmode = false;
this.form.reset();
$('#myModal').modal('show');
},
editModal(application) {
this.editmode = true;
this.form.reset();
$('#myModal').modal('show');
this.form.fill(application);
},
deleteApplication(id) {
Swal.fire({
title: 'Are you sure?',
text: "You won't be able to revert this!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, delete it!'
}).then((result) => {
if (result.isConfirmed) {
this.form.delete('api/application/' + id).then(() => {
Swal.fire(
'Deleted!',
'Application has been deleted.',
'success'
);
this.loadApplication();
}).catch((result) => {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: 'Something went wrong!',
})
});
}
})
},
loadApplication() {
axios.get("api/application").then(({ data }) => (this.applications = data));
},
loadUserID() {
axios.get('api/applicationGetID').then(({ data }) => (this.userID = data));
console.log(this.form.user_id);
// axios.get('api/applicationGetID').then(({ data }) => (this.userID2 = data.[id]));
},
// loadCatId() {
// axios.get('api/categoryId').then(({ data }) => (this.catIDs = data));
// },
createApplication() {
// this.form.newUserID = this.userID;
console.log(this.form.user_id)
this.form.post('api/application')
.then(() => {
$('#myModal').modal('hide');
Swal.fire('Application created!')
this.loadApplication();
})
.catch(() => {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: 'Something went wrong!',
})
})
}
},
created() {
this.loadApplication();
this.loadUserID();
// this.loadCatId();
}
}
</script>
The modal opens. The "Id" value is displayed in the readonly textbox with id = "Id". But the Description value does not display in the readonly textbox with the id = "Description". I stepped through the code and the correct value is present in the function on the master view. However, it is not displaying in the modal. Am I missing something? Why is the value not passing to the Description id in the partial?
Partial
#model AutoClickItOnline.Models.AdminViewModels.DeleteSubTypeViewModel
#{
Layout = null;
}
#using (Html.BeginForm("DeleteSubType", "Admin", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, null, new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-12">
<label for="Id" class="text-dark">Subscription Type ID</label>
#Html.TextBoxFor(m => m.SubTypeId, new { #class = "form-control", #readonly = true, id = "Id" })
<label for="Name" class="text-dark pt-2">Descripiton</label>
#Html.TextBoxFor(m => m.Description, new { #class = "form-control", #readonly = true, id = "Description" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-success">Delete Subscription Type</button>
</div>
</div>
}
Javascript:
#section Scripts{
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#user_table').DataTable({
"scrollY": "50vh",
"scrollX": true,
"autowidth": false
});
});
function DeleteSubType(id, Description) {
$('#Id').val(id);
$('#Description').val(Description);
$('#DeleteSubTypeModal').modal('show')
}
</script>
}
Main View:
#model AutoClickItOnline.Models.AdminViewModels.SubscriptionTypeTableViewModel
#{
ViewBag.Title = "SubTypes";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<section>
<div class="container">
<div class="row py-5">
<div class="col">
<div class="modal fade" id="newSubTypeModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">New Subscription Type Entry</h2>
</div>
<div class="modal-body">
#{
Html.RenderPartial("/Views/Admin/AddSubTypePartial.cshtml", new SubscriptionType());
}
</div>
</div>
</div>
</div>
<div class="modal fade" id="DeleteSubTypeModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">Delete Subscription</h2>
</div>
<div class="modal-body">
#{
Html.RenderPartial("/Views/Admin/DeleteSubTypePartial.cshtml", new AutoClickItOnline.Models.AdminViewModels.DeleteSubTypeViewModel());
}
</div>
</div>
</div>
</div>
<div class="d-flex flex-row">
<h2 class="pr-2">Subscription Type Manager</h2>
<a class="btn btn-sm btn-primary ml-auto my-2 text-light text-center d-none d-md-block" href="#" data-toggle="modal" data-target="#newSubTypeModal"><i class="fa fa-plus text-light pr-1"></i>Add New Subscription Type</a>
<a class="btn btn-sm btn-primary ml-auto my-2 text-light text-center d-sm-none" style="max-height:50px;" href="#" data-toggle="modal" data-target="#newSubTypeModal">ADD NEW</a>
</div>
#if (Model.Message != null)
{
<div class="text-danger">
#Html.DisplayFor(modelItem => Model.Message, null, new { #class = "text-danger" })
</div>
}
<hr />
<table id="user_table" class="display small-table table-bordered border-dark" style="width:100%;">
<thead>
<tr>
<th style="font-size:11px; min-width:195px;">Id</th>
<th style="font-size:11px;">Description</th>
<th style="font-size:11px;">Length</th>
<th style="font-size:11px;">Cost</th>
<th style="font-size:11px;">Active</th>
<th style="font-size:11px; min-width:100px;">Date/Time Created</th>
<th style="font-size:11px; min-width:60px;">Created By</th>
<th style="font-size:11px; min-width:105px;">Date/Time Modified</th>
<th style="font-size:11px; min-width:65px;">Modified By</th>
<th style="font-size:11px;">Delete</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.SubscriptionTypes)
{
<tr>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.SubscriptionTypeId)</td>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.Description)</td>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.Length)</td>
<td style="font-size:11px">$#Html.DisplayFor(modelItem => item.Cost)</td>
#if (item.Active)
{
<td style="font-size:11px">Yes</td>
}
#if (!item.Active)
{
<td style="font-size:11px">No</td>
}
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.DateTimeCreated) UTC</td>
<td style="font-size:11px">#AdminHelpers.GetUsersName(item.CreatedBy)</td>
<td style="font-size:11px">#Html.DisplayFor(modelItem => item.DateTimeModified) UTC</td>
<td style="font-size:11px">#AdminHelpers.GetUsersName(item.ModifiedBy)</td>
<td>
<input type="button" class="btn btn-sm btn-danger" value="X" onclick="DeleteSubType('#item.SubscriptionTypeId', '#item.Description'); return false;" />
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</section>
I try to update my recipe which has collection of ingredients(formArray) and i have problem with that because of formArray.
I have error on console:
ERROR Error: formArrayName must be used with a parent formGroup directive
When i update recipe without formArray(ingredients) it's working fine.
Could you give me a hint ?
It's my first time when i'm working with formArrays..
My code:
Component.ts
export class RecipeEditComponent implements OnInit {
#ViewChild('editForm') editForm: NgForm;
recipe: IRecipe;
photos: IPhoto[] = [];
ingredients: IIngredient[] = [];
uploader: FileUploader;
hasBaseDropZoneOver = false;
baseUrl = environment.apiUrl;
currentMain: IPhoto;
constructor(private route: ActivatedRoute, private recipeService: RecipeService,
private toastr: ToastrService) { }
ngOnInit(): void {
this.loadRecipe();
}
Html
<div class="container mt-4 border" *ngIf="recipe">
<form #editForm="ngForm" id="editForm" (ngSubmit)="updateRecipe(recipe.id)" >
<h5 class=" text-center mt-2">Recipe details:</h5>
<div class="form-group mt-3">
<label for="city">Name</label>
<label for="city">{{recipe.id}}</label>
<input class="form-control" type="text" name="name" [(ngModel)]="recipe.name">
</div>
<div class="form-group">
<div formArrayName="ingredients"
*ngFor="let ingredient of recipe.ingredients; let i = index;">
<div formGroupName= {{i}} class="row">
<div class="form-group col-6">
<app-text-input formControlName="name" [label]='"Name"' name="ingredient[i].name"></app-text-input>
</div>
<div class="form-group col-6">
<app-text-input formControlName="amount" [label]='"Amount"' [type]="'number'" name="ingredient[i].amount"></app-text-input>
</div>
</div>
</div>
</div>
<h5 class=" text-center mt-4">Description</h5>
<angular-editor cols=100% rows="6" [placeholder]="'Your description'" [(ngModel)]="recipe.description" name="description"></angular-editor>
</form>
<h3 class="text-center">Photos</h3>
<div class="row">
<div class="col-sm-2" *ngFor="let photo of recipe.recipePhotos">
<img src="{{photo.url}}" class="img-thumbnail p-1" alt="">
<div class="text-center">
<button type="button" class="btn btn-sm mr-1 mb-2"
(click) = "setMainPhoto(photo)"
[disabled]="photo.isMain"
[ngClass] = "photo.isMain ? 'btn-danger active' : 'btn-secondary'"
>Main</button>
<button type="button" class="btn btn-sm btn-danger mb-2"
(click)="deletePhoto(photo.id)" >
<i class="fa fa-trash-o"></i></button>
</div>
</div>
</div>
<div class="row justify-content-md-center mt-5 border">
<div class="col col-sm-4">
<div class="mt-4 text-center">
Multiple
<input type="file" ng2FileSelect [uploader]="uploader" multiple="true" /><br/>
Single
<input type="file" ng2FileSelect [uploader]="uploader" />
</div>
</div>
<div class="col col-sm-6">
<div ng2FileDrop
[ngClass]="{'nv-file-over': hasBaseDropZoneOver}"
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
class="card bg-faded p-3 text-center mt-3 mb-3 my-drop-zone">
<i class="fa fa-upload fa-3x"></i>
Drop Photos Here
</div>
</div>
</div>
<div class="col-md-6 mt-5" style="margin-bottom: 40px" *ngIf="uploader?.queue?.length">
<h3 class="text-center">Upload queue</h3>
<p>Queue length: {{ uploader?.queue?.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Name</th>
<th>Size</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.options.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.options.isHTML5">
</tr>
</tbody>
</table>
<div>
<div>
Queue progress:
<div class="progress mb-4" >
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
<span class="fa fa-upload"></span> Upload
</button>
<button type="button" class="btn btn-warning btn-s"
(click)="uploader.cancelAll()" [disabled]="!uploader.isUploading">
<span class="fa fa-ban"></span> Cancel
</button>
<button type="button" class="btn btn-danger btn-s"
(click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
<span class="fa fa-trash"></span> Remove
</button>
</div>
</div>
<button [disabled]="!editForm.dirty" form="editForm" class="btn btn-success btn-block mb-5 mt-5">Save changes</button>
</div>
This is how my recipe looks like with properties:
Problem Description
The directive formArrayName is a ReactiveForm directive and for it to work you must have below satisfied
Must have a parent formGroup
You must have imported ReactiveFormModule in your module
Solution
You may have to do some changes to implement this, see below
See Demo On Stackblitz
name = 'Angular ' + VERSION.major;
recipe = {
id: 1,
name: 'Test Recipe',
ingredients: [{
name: 'Chicken',
amount: 5
},
{
name: 'Pasta',
amount: 50
}],
description: 'Test Description'
}
ngForm = this.fb.group({
description: [this.recipe.description],
name: [this.recipe.name],
ingredients: this.fb.array(
this.recipe.ingredients.map(
ingredient => this.fb.group({
name: [ingredient.name],
amount: [ingredient.amount]
})
)
)
})
updateRecipe() {
}
<form [formGroup]="ngForm" id="editForm" (ngSubmit)="updateRecipe()">
<h5 class=" text-center mt-2">Recipe details:</h5>
<div class="form-group mt-3">
<label for="city">Name</label>
<label for="city">{{recipe.id}}</label>
<input class="form-control" type="text" formControlName='name'>
</div>
<div class="form-group">
<div formArrayName="ingredients" *ngFor="let ingredient of recipe.ingredients; let i = index;">
<div formGroupName={{i}} class="row">
<div class="form-group col-6">
<app-text-input formControlName="name" [label]='"Name"' name="ingredient[i].name">
</app-text-input>
</div>
<div class="form-group col-6">
<app-text-input formControlName="amount" [label]='"Amount"' [type]="'number'"
name="ingredient[i].amount"></app-text-input>
</div>
</div>
</div>
</div>
<h5 class=" text-center mt-4">Description</h5>
<angular-editor cols=100% rows="6" [placeholder]="'Your description'"
formControlName='description'></angular-editor>
</form>
Instead of using FormArrays in your template, try using NgModel for input data-binding:
<div class="form-group" *ngFor="let ingredient of recipe.ingredients; let i = index;">
<div class="form-group col-6">
<input [(ngModel)]="ingredient.name" />
</div>
<div class="form-group col-6">
<input [(ngModel)]="ingredient.amount" />
</div>
</div>
I have the following code snippet of my routes from app.js
let routes = [{
path: "/dashboard",
component: require("./components/Dashboard.vue")
},
{
path: "/tour",
component: require("./components/Index.vue"),
children: [{
name: 'create',
path: '/create',
component: require('./components/product/Create.vue')
}]
},
{
path: "*",
component: require("./components/NotFound.vue")
}
];
Master.blade.php
<div class="sidebar">
<router-link class="btn btn-success" to="/dashboard">
Dashboard
</router-link>
<router-link class="btn btn-success" to="/tour">
Tour
</router-link>
</div>
<div class="content">
<router-view></router-view>
</div>
Index.vue
<template>
<div class="container">
<div class="row mt-5">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Tours</h3>
<div class="card-tools">
<router-link class="btn btn-success" to="/tour/create">
Add New
<i class="fas fa-plus fa-fw"></i>
</router-link>
</div>
</div>
<!-- /.card-header -->
<div class="card-body table-responsive p-0">
<table class="table table-hover text-center">
<tbody>
<tr>
<th>ID</th>
<th>Name</th>
<th>Days</th>
<th>Price</th>
<th>Type</th>
<th>Image</th>
<th>Meta Title</th>
<th>Meta Description</th>
<th>Actions</th>
</tr>
<tr v-for="tour in tours.data" :key="tour.id">
<td>{{tour.id}}</td>
<td>{{tour.title}}</td>
<td>{{tour.days}}</td>
<td>{{tour.price}}</td>
<td>{{tour.category_id}}</td>
<td>
<i class="fas fa-check text-success" v-if="tour.image"></i>
<i class="fas fa-times text-danger" v-else></i>
</td>
<td>
<i class="fas fa-check text-success" v-if="tour.meta_title"></i>
<i class="fas fa-times text-danger" v-else></i>
</td>
<td>
<i class="fas fa-check text-success" v-if="tour.meta_description"></i>
<i class="fas fa-times text-danger" v-else></i>
</td>
<td>
<button #click="editModal(tour)" class="btn btn-primary btn-sm">Edit</button>
<button
#click="deleteUser(tour.id)"
class="btn btn-danger btn-sm"
>Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- /.card-body -->
<div class="card-footer"></div>
</div>
<!-- /.card -->
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
tours: ""
};
},
methods: {
initialLoad() {
axios.get("api/tour").then(({
data
}) => (this.tours = data));
}
},
created() {
this.initialLoad();
}
};
</script>
Index.vue shows all the tours that are saved in database.
Add New button is placed in Index.vue to load the Create.vue component in order to create tours.
But clicking on the create button loads NotFound.vue component from * route. No message of any type is given out during mixing and in console.
I also tried:
import create from './components/product/Create.vue';
and replacing component: require('./components/product/Create.vue') with create
And still no progress.
Can anyone point out the my mistake i'm doing here.
create a new file and Save by Tourview.vue inside the components folder.
<template>
<router-view ></router-view>
</div>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
};
};
</script>
and update your routing file like following.
let routes = [{
path: "/dashboard",
component: require("./components/Dashboard.vue")
},
{
path: "/tour",
component: require("./components/Tourview.vue"),
children: [
{
path:'',
component: require("./components/Index.vue")
},
{
name: 'create',
path: '/create',
component: require('./components/product/Create.vue')
}]
},
{
path: "*",
component: require("./components/NotFound.vue")
}
];
This question already has answers here:
ES6 array map doesn't return anything: ReactJS
(2 answers)
Closed 4 years ago.
I am trying to create a reactJs page that allows an admin add a user to a platform. Now, instead of submitting the form for each new user, I want the admin to be able to add as many users as possible before submitting the form. By default, one table row containing input fields is displayed and then on click of the add button, a new row is added and the admin can fill the necessary details. However, I can't get my page to show the default row and the add button does not work either and unfortunately, my page throws no error. Here is my code:
export default class Admins extends React.Component{
constructor(props){
super(props);
this.state = {
errors : '',
success : '',
rows : [1]
}
this.addRow = this.addRow.bind(this);
this.fetchRows = this.fetchRows.bind(this);
}
addRow(){
var last = this.state.rows[this.state.rows.length-1];
var current = last + 1;
this.setState({
rows : this.state.rows.concat(current)
});
}
fetchRows(){
this.state.rows.map((row, index) => (
//console.log(row, index)
<tr key={row}>
<td className="text-center">
<button type="button" data-toggle="tooltip" className="btn btn-xs btn-danger"
data-original-title=""><i className="fa fa-trash"></i>
</button>
</td>
<td>
<input type="text" className="form-control"/>
</td>
<td>
<input type="text" className="form-control"/>
</td>
<td>
<input type="text" className="form-control"/>
</td>
</tr>
));
}
render(){
return(
<div>
<Top/>
<SideBar/>
<div className="breadcrumb-holder">
<div className="container-fluid">
<ul className="breadcrumb">
<li className="breadcrumb-item"><Link to="/">Dashboard</Link></li>
<li className="breadcrumb-item active">Admins</li>
</ul>
</div>
</div>
<section className="forms">
<div className="container-fluid">
<header>
<h3 className="h5 display">Admins</h3>
</header>
<div className="row">
<div className="col-lg-6">
<h5 className="text-danger">{this.state.errors}</h5>
<h5 className="text-success">{this.state.success}</h5>
</div>
</div>
<div className="row">
<div className="col-lg-6">
<div className="card">
<div className="card-header d-flex align-items-center">
<h5></h5>
</div>
<div className="card-body">
<table className="table table-bordered">
<thead>
<tr>
<th width="5%">Actions</th>
<th>Name</th>
<th>Email</th>
<th>Password</th>
</tr>
</thead>
<tbody>
{this.fetchRows()}
<tr>
<td className="text-center">
<button type="button" onClick={this.addRow} data-toggle="tooltip" className="btn btn-xs btn-primary"
data-original-title=""><i className="fa fa-plus"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
}
}
You are not returning anything from fetchRows. Return it or simply put it directly in the render method and it will work as expected.
Example
class Admins extends React.Component {
state = {
errors: "",
success: "",
rows: [1]
};
addRow = () => {
var last = this.state.rows[this.state.rows.length - 1];
var current = last + 1;
this.setState({
rows: this.state.rows.concat(current)
});
};
render() {
return (
<div>
<div className="breadcrumb-holder">
<div className="container-fluid">
<ul className="breadcrumb">
<li className="breadcrumb-item active">Admins</li>
</ul>
</div>
</div>
<section className="forms">
<div className="container-fluid">
<header>
<h3 className="h5 display">Admins</h3>
</header>
<div className="row">
<div className="col-lg-6">
<h5 className="text-danger">{this.state.errors}</h5>
<h5 className="text-success">{this.state.success}</h5>
</div>
</div>
<div className="row">
<div className="col-lg-6">
<div className="card">
<div className="card-header d-flex align-items-center">
<h5 />
</div>
<div className="card-body">
<table className="table table-bordered">
<thead>
<tr>
<th width="5%">Actions</th>
<th>Name</th>
<th>Email</th>
<th>Password</th>
</tr>
</thead>
<tbody>
{this.state.rows.map((row, index) => (
//console.log(row, index)
<tr key={row}>
<td className="text-center">
<button
type="button"
data-toggle="tooltip"
className="btn btn-xs btn-danger"
data-original-title=""
>
<i className="fa fa-trash" />
</button>
</td>
<td>
<input type="text" className="form-control" />
</td>
<td>
<input type="text" className="form-control" />
</td>
<td>
<input type="text" className="form-control" />
</td>
</tr>
))}
<tr>
<td className="text-center">
<button
type="button"
onClick={this.addRow}
data-toggle="tooltip"
className="btn btn-xs btn-primary"
data-original-title=""
>
<i className="fa fa-plus" />
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
}
}