Using same form for insert and edit - forms

How can I use the same form for inserting and editing a document in Meteor.
For insert I use empty form without variable:
<template name="frmOrganization">
// no doc variable
<form class="form-horizontal" role="form">
...
<input type="text" class="form-control" id="Name">
And for update I use form with variable:
<template name="frmOrganization">
{{#with organization}} // doc variable
<form class="form-horizontal" role="form">
...
<input type="text" class="form-control" id="Name" value="{{Name}}">

(Using Meteor 0.9.3 + Iron-Router)
I had the same issue and the workaround I used was as follows (seems to be more of a hack but I get to avoid having multiple forms)
<template name="frmOrganization">
// no doc variable
<form class="form-horizontal" role="form">
...
<input type="text" class="form-control" id="Name" value={{name}}>
{{#if name}}
<input type="submit" value="Edit"/>
<input type="submit" value="Delete"/>
{{else}}
<input type="submit" value="Add"/>
{{/if}}
...
In my router.js file
this.route('frmOrganization', {
path: '/organisation/:_id/edit',
data: function() { return Organisation.findOne(this.params._id); }
});
All seems pretty standard, but then for my Add link, I use:
Add
Which will create he following link:
/organisation/null/edit
The null page gives you your Add page and an ID would give you your edit page.
-- Meteor Noob

A simple way would be to use an upsert with the _id of the organization document as the first argument. If nothing is found in the collection when you try to upsert, then it will insert the data into a new document (second argument).
However, there are some packages which can make this task much easier:
autoform, simple-schema and collection2
(I would link to the others but lack the reputation)
Firstly define a schema and apply it to the collection as follows:
Pages = new Meteor.Collection('pages');
PagesSchema = new SimpleSchema({
title: {
type: String,
label: 'Title',
max: 100
},
body: {
type: String,
label: 'Body',
max: 1000
}
});
Pages.attachSchema(PagesSchema);
Then it's possible to simply switch these two templates for an insert or update:
{{> quickForm collection="Pages" id="page-form" type="insert"}}
{{> quickForm collection="Pages" doc=page id="page-form" type="update"}}
(With 'page' being the document itself available in the template)
These handlebars helpers will produce the entire form, and you can even validate with them.

Say that you have a create form at path /my-form. This is fairly straightforward. It creates a new document in your database with an :_id of, say, XYZ123.
Now you want an edit form.
You create a link that goes to /my-form/XYZ123
You've created a path with the document :_id as a parameter.
You then set your route to read the :_id parameter of your path as data. (Look at the Discover Meteor book for an example)
Now add code to your existing form that will take that :_id from the path, do a lookup for the document, and pre-populate the values in the form with the values it finds from the database based off of that :_id.
And change the submit button to do an update instead of insert.
As for delete, that's simple. No extra form needed. On the edit form just create a big red delete button that will delete the document with that :_id.
Write your JS so that if there is a parameter in the path, make the delete button visible and turn the submit button from insert into update.

Related

salesforce lightning this.template.querySelector not working

<template>
<div class="container-wrapper">
<div if:false={loggedIn} class="slds-m-around_medium">
<span>Login to Salesforce App</span>
<lightning-input name='username' label="Username"></lightning-input>
<lightning-input type="password" name='password' label="Password"></lightning-input>
<br/>
<lightning-button variant="brand" label="Login" title="Login" onclick={login}></lightning-button>
</div>
</div>
</template>
login() {
console.log('login attempt');
console.log(this.template);
var Username =this.template.querySelector('input[name="username"]').value;
var Password =this.template.querySelector('input[name="password"]').value;
console.log(Password);
console.log(Username );
}
values are not getting fetch in username, password variables.
this.template.querySelector('input[name="username"]').value is not working.
I have also tried onchange event approach on lightning-input elements , in that case event.target was undefined ? I am stuck not able to read user input.
app screenshot
There is no property 'name' on lightning-input like on standard HTML input. You should use 'data-id' instead.
HTML:
<lightning-input data-id='username' label="Username"></lightning-input>
JS:
let username = this.template.querySelector('lightning-input[data-id=username]');
The <template> element is not a common element. It holds its (inactive) DOM content inside a Document Fragment that you can access through the content property.
Therefore you should try:
var Username = this.template.content.querySelector('input[name="username"]').value;
var Password = this.template.content.querySelector('input[name="password"]').value;
In Salesforce when you are accessing a lightning input using the query selector first you have to search for lightning-input tag not the input tag.
Secondly when you add a name attribute to the lightning-input that attribute is transfered to the input tag which is created when the lightning component is rendered. But you can not access the input tag (my assumption is that it's in the Shadow DOM). Therefore to search for the lighting-input you must use a class name to identify the lightning component.
<lightning-input type="number" class="optionEditQuantityVal" value={Quantity} variant="label-hidden" step="1" max-length="1"></lightning-input>
let input = this.template.querySelectorAll('lightning-input.optionEditQuantityVal')

SailsJs ajax-form validation

Is there a way I can run a function on the built-in vue component "ajax-form" in SailsJs? I want it to run when the form is submitted and do some validation, but take place before the data is sent to the back end.
Ajax-form is super handy. And it's well supported by Sails.js
Here is an example of how you can set up your form:
<ajax-form action="createOneThing" :syncing.sync="syncing" :cloud-error.sync="cloudError"
:form-errors.sync="createThingFormErrors" :form-data="createThingFormData"
:form-rules="createThingFormRules" #submitted="submittedCreateThingForm($event)">
<label for="thing-name">Thing Name:</label>
<input class="form-control" :class="[createThingFormErrors.thingName ? 'is-invalid' : '']"
type="text" id="thing-name" v-model="createThingFormData.thingName">
<div class="invalid-feedback" v-if="createThingFormErrors.thingName">Make up a name for your thing.</div>
<ajax-button type="submit" :syncing="syncing">Delete</ajax-button>
</ajax-form>
Now you have to make sure you set your objects in your page script under data:
createThingFormData: {},
createThingFormErrors: {},
createThingFormRules: {
thingName: { required: true },
}
You can also check out this post for more usage info about Ajax
https://www.formget.com/form-validation-using-ajax/

How to edit an item which is created using a single form on Angular2?

I am new to angular2 & I have a form which can add more item to a page (item with name & decription). This works really well, I can keep on adding new item to my list.
However, each of this item has its own edit & delete. How can I edit and delete each of the item using that only 1 form?
<form #formExperiencesRef="ngForm">
<label for="name">name</label>
<input id="name" type="text" name="fruit [(ngModel)]="formData.name">
<label for="description">description</label>
<input id="description" type="text" name="fruit [(ngModel)]="formData.description">
<button (click)="onSubmit(formExperiencesRef.value)"></button>
</form>
This single form is what I use to keep on adding new item. And now I find it hard to edit the item that I created using this. Can someone help me?
Often I would advise to go with a reactive form for all it's benefits, but if your form is this simple a template driven approach can be sufficient.
First of all I see problem in your form. Your name attributes are the same for both fields, this will mean that they are evaluated as one and the same. I would actually name them as for how your formData object looks like, and then just push the form value as is to the array. I'll just use one way binding here for the sake of the editing of item. Also pass the form object in submit.
How we can edit can be done numerous ways. Here we'll utilize the index of your list (assumingly it's an array).
<form #formExperiencesRef="ngForm" (ngSubmit)="onSubmit(formExperiencesRef.value)">
<input name="name" [ngModel]="formData.name">
<input name="description" [ngModel]="formData.description">
<button type="submit">Submit</button>
</form>
Your list:
<div *ngFor="let item of items; let i = index">
{{item.name}} <button (click)="edit(item, i)">Edit</button>
</div>
And in the TS, we can use #ViewChild to reference our form, which I am using to reset the form:
#ViewChild('formExperiencesRef') formExperiencesRef: NgForm;
and your methods for editing and saving a new item:
formData = {};
items = [];
index = null; // used to store current index value of item (if exists)
edit(item, i) {
this.index = i;
this.formData = item;
}
onSubmit(val) {
// check if index exists, if not it's a new item
if(this.index == null) {
this.items.push(val)
} else {
this.items[this.index] = val;
}
// reset index & form
this.index = null;
this.formExperiencesRef.reset();
}
DEMO: http://plnkr.co/edit/ksHp10WwaDg4AQjwDf2d?p=preview
For the future, I really suggest you check out reactive forms, you have tighter control over your form, handle validations easier and a big,big advantage to me is especially if you are dealing with nested components. Reactive forms can be confusing in the beginning, but it's worth it! :)

Meteor: how to accept user input in a set of form fields

New to Meteor. I have a form with several fields
<template name="addcityform">
<form name="addcity">
<input name="city" class="city" type="text">
<input name="population" class="population" type="text">
<input type="Submit" value="Add City">
</form>
</template>
I just want to insert the fields into the database, but I'm stumped on how to do it. Here's what I currently have after several attempts:
Template.addcityform.events({
'submit .addcity' : function(evt, template) {
Cities.insert({
city: template.find('input.city').value,
population: template.find('input.population').value
});
}
});
// this gives: Uncaught TypeError: Cannot read property 'value' of null
I saw some examples that use Session.set and document.getElementById, but that seems clumsy to me due to the potential for namespace conflicts. I'd like to do this the 'right way' so that it's extensible later, for example, I could put multiple instances of the form onto the page and they should be independent of each other. What is the 'right way' to do this?
You lack an event.preventDefault() in the "submit form" handler, or else the page will reload and ruin the single-page app experience of Meteor.
I would do something like :
<template name="addcityform">
<form>
<input name="city" class="city" type="text">
<input name="population" class="population" type="text">
<button type="submit">Add City</button>
</form>
</template>
Template.addcityform.events({
"submit form": function(event, template) {
event.preventDefault();
Cities.insert({
city: template.find(".city").value,
population: template.find(".population").value
});
}
});
What's cool about Meteor templates is that css selectors used within them are local to the current template, meaning that "submit form" will always refer to "submit event of the form element in enclosing template", given that you only have one form in the template.
The same applies to template instances .find method : it will return an element matching the css selector within the template or its sub-templates.
This allows you to have multiple instances of your addcityform that will be independent from each other.

Angular JS: sending form field data in a PUT request (like POST does)

I'm trying to write a client that does all four REST verbs (GET/POST/PUT/DELETE) and have gotten all but the PUT done. The REST/CRUD API I'm working from wants to update an entry by calling PUT /realmen/ID-string and including the key-value pairs as JSON. For a POST this seems to work "automatically", but not for a PUT.
My HTML looks like:
<div id="list">
<form novalidate class="edit-form">
<p>Title <input ng-model="realmen.title" type="text" value="{{realmen.title}}" /></p>
<p>Real Men <input ng-model="realmen.realmen" type="text" value="{{realmen.realmen}}" /> </p>
<p>Real Role-Players <input ng-model="realmen.realroleplayers" type="text" value="realmen.realroleplayers}}" /></p>
<p>Loonies <input ng-model="realmen.loonies" type="text" value="{{realmen.loonies}}" /></p>
<p>Munchkins <input ng-model="realmen.munchkins" type="text" value="{{realmen.munchkins}}" /></p>
<input ng-model="realmen.entryId" type="hidden" value="{{entryId}}"/>
<button ng-click="change()">UPDATE ({{entryId}})"</button></p>
</form>
</div>
My controller looks like:
$scope.realmen = RealMen.get({entryId: $routeParams.entryId}, function() {
$scope.master = angular.copy($scope.realmen); // For resetting the form
});
$scope.change = function() {
console.log($scope.realmen);
RealMen.update({entryId: $scope.entryId}, function() {
$location.path('/');
});
}
And finally, my services look like:
angular.module('realmenServices', ['ngResource']).
factory('RealMen', function($resource){
var RealMen = $resource(
'http://localhost\\:3000/realmen/:entryId',
{},
{
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method: 'PUT', params:{entryId:'#entryId'}},
remove: {method:'DELETE'}
});
return RealMen;
});
The PUT is getting called with the correct id value in the URL, but the Request Payload only contains the entryId, so the backend API gets no expected keys and values and essentially blanks out the record in the database.
The console.log($scope.realmen) does show the form fields, along with a lot of extra data. I tried calling RealMen.update($scope.realmen, ...) (similarly to calling .save()), but all those extra fields are tacked on as query string parameters to the URL in a spectacularly ugly fashion.
Because your $scope.realmen is a resource instance, instead of using RealMen.update, you can just call $scope.realmen.$update() (note that there is a "$"). The instance action method will take care of sending the data for you.