Aurelia validation nor working when data is pre-populated in the form - validation

I have been unable to get the validation to work on an edit model-view that has data bound to it in the activate method of its view-model.
I have a created.ts which works on an object with the same fields. This file has almost the same code - the exception is that since this one is a create, no data needs to be loaded to it. In this case, the validation is working properly.
If I comment the code that loads the data for the edit model-view - in the activate method - the validation works properly.
Needless to say I am new to SPA, Aurelia and TypeScript and need some help!!
Below is the code in edit.ts
import { ContactRepository } from "./contactRepository";
import { autoinject } from "aurelia-framework";
import { ContactForEditDto } from "./contactForEditDto";
import { json } from "aurelia-fetch-client";
import { inject, NewInstance } from "aurelia-dependency-injection";
import { ValidationRules, ValidationControllerFactory, validateTrigger,
Validator } from "aurelia-validation";
#autoinject
export class Edit {
public saveStatusMessage: string;
public isSaved: number = -1;
private controller = null;
private validator = null;
public canSave: boolean = false;
constructor(public contactForEdit: ContactForEditDto, private repository:
ContactRepository, private controllerFactory: ValidationControllerFactory,
public contactFullName: string, validator: Validator) {
console.log("starting edit controller");
this.controller = controllerFactory.createForCurrentScope(validator);
this.controller.validateTrigger = validateTrigger.changeOrBlur;
this.validator = validator;
this.controller.subscribe(event => this.validateWhole());
ValidationRules
.ensure((c: ContactForEditDto) => c.contactFirstName)
.displayName("First Name")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactLastName)
.displayName("Last Name")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactEmailAddress)
.displayName("Email Address")
//.required().withMessage("\${$displayName} cannot be empty.")
.email().withMessage("\${$displayName} needs to be in a correct email address format.")
.maxLength(50).withMessage("\${$displayName} cannot have more than 50 characters.")
.ensure((c: ContactForEditDto) => c.contactPhoneNumber)
.displayName("Phone Number")
.required().withMessage("\${$displayName} cannot be empty.")
.maxLength(12).withMessage("\${$displayName} cannot have more than 12 characters.")
.matches(/\d{3}-\d{3}-\d{4}/).withMessage("'${$value}' is not a valid \${$displayName}. Please enter a phone in the format xxx-xxx-xxxx")
.on(ContactForEditDto);
}
// source https://www.jujens.eu/posts/en/2017/Jan/24/aurelia-validation/
workaround 3
validateWhole() {
this.validator.validateObject(this.contactForEdit)
.then(results => this.canSave = results.every(result => result.valid));
}
// Returning data from here because I can return a promise
// and let the router know when i have retrieved my initial data.
// Activate receives a params object as defined in the route.
activate(params) {
console.log("ACTIVATE ON EDIT PARAMS:" + params);
this.repository
.getById(params.id)
.then(data => {
console.log(data);
this.contactForEdit = data;
this.contactFullName = this.contactForEdit.contactLastName + ", " +
this.contactForEdit.contactFirstName; // This needs to come from a method
in
contact.
});
}
edit() {
this.saveStatusMessage = "";
this.isSaved = -1;
// This will be an edit
if (this.contactForEdit.contactId >= 1) {
this.repository
.update(this.contactForEdit)
.then(response => {
if (((response.status == 201) || (response.status == 204))
&& (response.ok == true)) {
this.isSaved = 1;
this.saveStatusMessage = "Successfully saved the contact";
}
else {
this.isSaved = 0;
//response.json().then(json => this.retVal = json);
//TODO: get more details about the error.
if (response.status == 400) {
this.saveStatusMessage = "Unable to save the contact. Please make sure that you entered correct values for every field and try again.";
}
else {
this.saveStatusMessage = "Unable to save the contact.";
}
}
});
}
}
clearContactFields() {
this.contactForEdit = new ContactForEditDto(-1, "", "", "", "");
}
}
Below is the code in edit.html
<template>
<form id="editContact" submit.delegate="edit()">
<!-- placeholder for status messages. If equal to 1 display it. If equals to
-1 or 1 hide this.-->
<div id="successStatusMessage" class.bind="isSaved == 1 ? 'visible' :
'hidden'">
<div id="divSuccessMessage" class="alert alert-success">
×
<!--<span class="glyphicon glyphicon glyphicon-ok" aria-hidden="true">
</span> TODO: How to get the glyphicon working? -->
<span class="sr-only"> Success:</span> ${saveStatusMessage}
</div>
</div>
<!-- placeholder for status messages. If equal to 0 is in error, so dislay error message. if equals to -1 or 1 hide this.-->
<div id="errorStatusMessage" class.bind="isSaved == 0 ? 'visible' : 'hidden'">
<!-- placeholder for status messages. -->
<div id="divErrorMessage" class="alert alert-danger">
×
<!-- <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> TODO: class="glyphicon glyphicon-exclamation-sign" how to get these in here for class? -->
<span class="sr-only"> Error:</span> ${saveStatusMessage}
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">
<!--<div if.bind="isCreate">
"Create a Contact"
</div>
<div if.bind="!isCreate">
Edit ${contactForEdit.contactFirstName}
</div>-->
${ "Edit " + contactFullName }
</div>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group" validation-errors.bind="editFirstNameErrors"
class.bind="editFirstNameErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">First Name: </label>
<div class="col-md-10">
<input type="text"
placeholder="First Name"
class="form-control"
value.bind="contactForEdit.contactFirstName & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editFirstNameErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="editLastNameErrors"
class.bind="editLastNameErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">Last Name: </label>
<div class="col-md-10">
<input type="text"
placeholder="Last Name"
class="form-control"
value.bind="contactForEdit.contactLastName & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editLastNameErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="emailErrors"
class.bind="editEmailErrors.length ? 'has-error' : ''">
<label for="emailAddress" class="control-label col-md-2">Email: </label>
<div class="col-md-10">
<input id="emailAddress"
type="text"
placeholder="Email Address (format: email#domain.com)"
class="form-control"
value.bind="contactForEdit.contactEmailAddress & validate" /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editEmailErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<div class="form-group" validation-errors.bind="editPhoneErrors"
class.bind="editPhoneErrors.length ? 'has-error' : ''">
<label class="control-label col-md-2">Phone: </label>
<div class="col-md-10">
<input type="text"
placeholder="Phone Number (format: xxx-xxx-xxxx)"
class="form-control"
value.bind="contactForEdit.contactPhoneNumber & validate" required /> <!-- NO ${} !!!-->
<span class="help-block" repeat.for="editErrorInfo of editPhoneErrors">
${editErrorInfo.error.message}
</span>
</div>
</div>
<button type="submit" class="btn btn-default ${canSave ? '' : 'disabled'}">
<!-- Look at click.dependent when there are child with buttons calling this.-->
Save
</button>
<!-- AA-10-17-17 - replaced with errors per input field. <ul for.bind="controller.errors">
<li repeat.for="error of controller.errors" style="color:red">
${error.message}
</li>
</ul>-->
</div>
</div>
</div>
</form>
<div>
<a route-href="route: home"
class="btn btn-default">
Back to list
</a>
</div>
</template>

I expect it's because of this code:
.getById(params.id)
.then(data => {
console.log(data);
this.contactForEdit = data;
your validation is against a ContactForEditDto object, but my guess is your repository is returning a JSON object cast to a ContactForEditDto, so it's not actually a class at all.
Try something like
console.log(data);
this.contactForEdit = new ContactForEditDto(data.id, data.firstname ..etc..);
or
console.log(data);
this.contactForEdit = Object.assign(new ContactForEditDto(), data);

We just had a similar problem and solved it by setting up our validations after assigning the remote data to our local field. In your code, you'd set up your validation rules after this.contactForEdit = data;

Related

Eloquent update doesn't work in Laravel 6

I'm trying to update a field after submitting in the following form:
<form action="{{ route("comments.update") }}" method="post">
#csrf
<input type="hidden" name="commentIDToEdit" id="commentID">
<div class="md-form mb-5">
<i class="fas fa-comment"></i>
<label for="toEditComment"></label>
<textarea name="toEditCommentary" id="toEditComment" cols="3" rows="5" style="resize: none"
class="form-control"></textarea>
</div>
<div class="modal-footer d-flex justify-content-center">
<button type="submit" class="btn btn-default">Modificar</button>
</div>
</form>
I have the CommentsController, where I process the data from the form. Here is the code:
public function updateComment()
{
request()->validate([
"toEditCommentary" => "min:10|max:500"
]);
if (Session::has("username") && getWarningCount(User::whereUsername(session("username"))->value("email")) > 0) {
Caveat::where("commentID", request("commentIDtoEdit"))
->update(["updatedComment" => request("toEditCommentary")]);
} else {
die("No se cumple la condición");
}
if (Comment::where("commentID", request("commentIDToEdit"))->exists()) {
Comment::where("commentID", request("commentIDToEdit"))
->update(["commentary" => request("toEditCommentary")]);
}
return back();
}
Curiosly, the comment is updated in his table, but not the warning. I was thinking in the fillable property in the model, but I don't have it, instead this, I have the following code:
protected $guarded = [];
const UPDATED_AT = null;
const CREATED_AT = null;
Your hidden input is named commentIDToEdit, but in the Controller you fetch the Caveat using request("commentIDtoEdit") (different case).
What you wrote:
Caveat::where("commentID", request("commentIDtoEdit"))
What you should have done: (note the different casing)
Caveat::where("commentID", request("commentIDToEdit"))
This is because in the view, the input name is commentIDToEdit, not commentIDtoEdit.

I want to update image using laravel

I am trying to update the image into database but unfortunately, the image is not updating into the database how to fix it. please help me thanks.
Controller
public function updateslider(Request $request, $id)
{
$this->validate($request, [
'select_image' => 'required'
]);
$image = $request->file('select_image');
$extension = $image->getClientOriginalExtension();
Storage::disk('cms')->put(
$image->getFilename() . '.' . $extension,
File::get($image)
);
$content = new Sliders;
if ($request->file('select_image')) {
$content->slider_image = $image->getFilename() . '.' . $extension;;
$updaterecord = sliders::where(['id' => $content->id])->update(['slider_image' =>
$content]);
return back()->with('success', 'Image Updated Successfully')->with('path', $updaterecord);
}
}
HTML view
<form method="post" action="
{{route('update.action',$myslider->id)}}"
enctype="multipart/form-data" >
#csrf
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<h4 class="header-title">Image Upload</h4>
<input type="file" name="select_image" value="
{{config('e_soft.file_url').$myslider->slider_image}}"
class="dropify" data-height="300" />
</div> <!-- end card-body-->
</div> <!-- end card-->
<div class="page-title-right">
<button type="submit" id="update" class="btn btn-danger
waves-effect waves-light col-lg-1">Update</button>
</div>
</div>
<!-- end row -->
</form>
Ok so I think your problem is that you want to set default value for <input type="file"> which is not possible. for security reasons you can't set default value for <input type="file"> so in your case you can check if there is a new image file you put the new one otherwise you just reassign previous slider image here is an example:
$slider = Sliders::findOrFail($id);
if (! empty($request->file('select_image'))) {
$content->slider_image = $image->getFilename().'.'.$extension;;
} else {
$content->slider_image = $slider->slider_image;
}
So as you can see first we check if there is a new file if so we assign new one otherwise we use the old one.

Toggle form in nested v-for loop in VueJS

I have a list of nested comments. Under each comment, I'd like to add a "reply" button that, when click, show a reply form.
For now, everytime I click a "reply" button, it shows the form. But the thing is, I'd like to show only one form on the whole page. So basically, when I click on "reply" it should close the other form alreay opened and open a new one under the right comment.
Edit :
So I was able to make some slight progress. Now I'm able to only have one active form opening on each level of depth in the nested loop. Obviously, what I'm trying to do now is to only have one at all.
What I did was emitting an event from the child component and handle everything in the parent component. The thing is, it would work great in a non-nested comment list but not so much in my case...
Here is the new code:
In the parentComponent, I have a handleSelected method as such:
handleSelected (id) {
if(this.selectedItem === id)
this.selectedItem = null;
else
this.selectedItem = id;
},
And my childComponent:
<template>
<div v-if="comment">
<div v-bind:style=" iAmSelected ? 'background: red;' : 'background: none;' ">
<p>{{ comment.author.name }}<br />{{ comment.created_at }}</p>
<p>{{ comment.content }}</p>
<button class="button" #click="toggle(comment.id)">Répondre</button>
<button class="button" #click="remove(comment.id)">Supprimer</button>
<div v-show="iAmSelected">
<form #submit.prevent="submit">
<div class="form-group">
<label for="comment">Votre réponse</label>
<textarea class="form-control" name="comment" id="comment" rows="5" v-model="fields.comment"></textarea>
<div v-if="errors && errors.comment" class="text-danger">{{ errors.comment[0] }}</div>
</div>
<button type="submit" class="btn btn-primary">Envoyer</button>
<div v-if="success" class="alert alert-success mt-3">
Votre réponse a bien été envoyée !
</div>
</form>
</div>
</div>
<div v-if="comment.hasReply">
<div style="margin-left: 30px;">
<comment v-for="comment in comments"
:key="comment.id"
:comment="comment" #remove-comment="remove"
:is-selected="selectedItem" #selected="handleSelected($event)">
</comment>
</div>
</div>
</div>
</template>
<script>
import comment from './CommentItem'
export default {
name: 'comment',
props: {
isSelected: Number,
comment: {
required: true,
type: Object,
}
},
data () {
return {
comments: null,
fields: {},
errors: {},
success: false,
loaded: true,
selectedItem: null,
}
},
computed: {
iAmSelected () {
return this.isSelected === this.comment.id;
}
},
methods: {
remove(id) {
this.$emit('remove-comment', id)
},
toggle(id) {
this.$emit('selected', id);
},
handleSelected(id) {
if(this.selectedItem === id)
this.selectedItem = null;
else
this.selectedItem = id;
},
},
mounted(){
if (this.comment.hasReply) {
axios.get('/comment/replies/' + this.comment.id)
.then(response => {
this.comments = response.data
})
}
}
}
</script>
Thanks in advance for your help!

GraphQL Apollo recieving data object undefined

I am doing a mutation, that takes a username and password, and in response from the server it gets a login response.
<Mutation mutation={SIGN_UP}>
{(signUp, data) => (
<form onSubmit={e => {
e.preventDefault();
signUp({
variables: {
user: {
"email": input_email.value as String,
"password": input_password.value as String
}
}
});
console.log("Signup", signUp)
console.log("Data", data.data);
input_email.value = "";
input_password.value = "";
}}>
<div className="col-sm">
<div className="signin__header">Signup IMPACT R&D</div>
</div>
<div className="col-sm signin__input" >
<div className="signin__input__header" >Email</div>
<input className="signin__input__email" type="text" placeholder="Enter email" required ref={node=> {input_email = node}}></input>
<div className="signin__divide-line"></div>
</div>
<div className="col-sm signin__input">
<div className="signin__input__header" >Password</div>
<input className="signin__input__password" type="password" placeholder="Enter password" ref={node=> {input_password = node}}></input>
<div className="signin__divide-line"></div>
</div>
<div className="col-sm-3">
<button className="signin__input__button" type="submit">Sign Up</button>
</div>
</form>
)}
</Mutation>
This is my GraphQLtag.
export const SIGN_UP : any = gql`
mutation Register($user: UserInput!) {
register(user: $user) {
status,
refreshToken,
token,
error
}
}
`;
in the browser network i can see that I receive the data. But still my data object is null, when i try to print it out... HELP!
Found out that i needed to wait for the response with a then promise after the signup
}).then ((res: any) => {
errorMessage = res.data.register.token;
});

Angular2 How to pass a method located in other file

I am quite a noob in Angular2 and typescript.
I want to pass a method from other class in a other file.
This is the file iam talking about in specific i want to pass the method deleteCondition():
export class ConditionBuilderComponent implements OnInit {
conditions: Condition[] = [];
catalog: Condition[] = [];
constructor(private _conditionService: ConditionService) { }
getConditions() {
this._conditionService.getConditions().then(conditions => this.catalog = conditions);
}
ngOnInit() {
this.getConditions();
}
onChange(conditionsIndex, catalogIndex) {
//console.log(selectedCondition);
//console.log(conditionsIndex);
console.log(catalogIndex);
this.conditions[conditionsIndex] = this.catalog[catalogIndex];
}
newCondition() {
this.conditions.push(this.catalog[0]);
}
deleteCondition() {
this.conditions.pop();
}
}
I want to pass the deleteCondition() method to an other file because in the other file this.conditions.pop() is not recognised of course.
First it was like this: https://www.dropbox.com/s/92z2oe7f4w5x2b5/conditions.jpg?dl=0
Here it deletes the last created but i want to delete each condition separately like this:
https://www.dropbox.com/s/ptwq6sk6da4p21k/new.jpg?dl=0
This is the code from the SelectCondition:
import {Component} from 'angular2/core';
import {Condition} from './condition';
import {ConditionBuilderComponent} from "./conditionbuilder.component";
#Component({
selector: 'select-condition',
template: `
<div class="col-xs-3">
<div class="form-group">
<select class="form-control" [(ngModel)]="selectedOperator">
<option *ngFor="#operator of selectOperators">{{operator}}</option>
</select>
</div>
</div>
<div class="col-xs-3">
<div class="form-group">
<div class="input-group">
<span class="btn-file">
<input type="file" (click)="selectFile()" multiple />
</span>
<input type="text" [(ngModel)]="fileValue" class="form-control" readonly>
<span class="input-group-addon">
<span class="glyphicon glyphicon-folder-open"></span>
</span>
</div>
</div>
</div>
<a class="btn btn-danger pull-right" (click)="deleteCondition()"><i class="glyphicon glyphicon-minus"></i></a>
`
})
export class SelectCondition extends Condition {
public name: string = 'select';
public fileValue: string;
public selectedOperator: string = 'in';
public selectOperators: Condition[] = [
"in"
];
selectFile() {
$(document).on('change', '.btn-file :file', function() {
var input = $(this),
numFiles = input.get(0).files ? input.get(0).files.length : 1,
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
input.trigger('fileselect', [numFiles, label]);
});
$('.btn-file :file').on('fileselect', function(event, numFiles, label) {
var input = $(this).parents('.input-group').find(':text'),
log = numFiles > 1 ? numFiles + ' files selected' : label;
if( input.length ) {
input.val(log);
console.log(input.val());
}
});
}
deleteCondition = () => this.deleteCondition();
}
Please help me out.

Resources