SimpleSchema and AutoForm: Render password field as single input - meteor

I'm working in a project where a "super admin" user can create another users, setting they usernames and passwords. I have an AutoForm quickForm rendering a form based upon the SimpleSchema attached to the Meteor.users collection (using Collection2).
Following the Collection2 docs recommendation on attaching a schema to the users collection, my schema looks like this:
Usuarios.schema = new SimpleSchema({
...
username: {
type: String,
},
services: {
type: Object,
optional: true,
blackbox: true
},
"services.password": {
type: String,
optional: true,
autoform: {
type: 'password'
}
},
...
});
The rendered form looks like this:
But I would like to have the Password field rendered like the Username one (without the Services panel).
I haven't found a workaround to this. I need to have the Services Object type atribute in the schema or the validation upon user insert fails (with Accounts.createUser()), and so, the panel is rendered (because of the Object type of the atribute).
Any ideas on how I could achieve the desired template rendering?

Your password is part of the 'service' object, which is why it is automatically rendered inside a afObjectField when using quickForm or quickFields:
afObjectField
When you use the afQuickField component for a field that is an Object,
it is rendered using the afObjectField component unless you override
the type or specify options. This happens by default when you use a
quickForm for a schema that has a field of type Object.
The afObjectField component renders all of an object field's subfields
together as one group. The group is labeled with the name of the
object field. The actual visual representation of the group will vary
based on which theme template you use. For the "bootstrap3" default
template, the group appears in a panel with a heading.
Solution A: Manual Form Rendering
To render your password as a single field, you need to set up your autForm manually and reference the fields by using afFieldInput. The form mthen may look like (not tested but code should look like) this:
{{> autoForm id="login" schema=Usuarios.schema}}
{{> afFieldInput type="text" name="username"}}
{{> afFieldInput type="password" name="services.password"}}
{{/autoForm}}
Which has the advantage that your form looks exactly as you wish but has the disadvantage, that you have to add all extras (validation messages and stuff) manually.
Solution B: Change your Schema
When you pull password out of the service group, then you will have the same effect of auto-render as with username: a single input field.
Usuarios.schema = new SimpleSchema({
...
username: {
type: String,
},
services: {
type: Object,
optional: true,
blackbox: true
},
...
password: {
type: String,
optional: true,
autoform: {
type: 'password'
}
},
...
});

Related

Best practice for Meteor AutoForm validation of items not in the form?

AutoForm works great when you want to validate a form using the schema, but oftentimes the form doesn't contain all the data that's in the schema, so you get a validation error.
For example, I have a submit button that is disabled until it determines the form is completely valid, but because the form doesn't contain all the data that's in the schema, it can never show that it's completely valid.
Say that you've got a schema
ShoppingCartSchema = new SimpleSchema({
itemsOrdered: {
type: [Object],
optional: false,
},
totalPrice: {
type: Number,
optional: false,
},
customerAddress: {
type: Object,
optional: false
},
systemGeneratedInfo: {
type: Object,
optional: true,
blackbox: true
},
});
ShoppingCarts.attachSchema(ShoppingCartSchema);
My form code would be something like:
{{> quickForm collection="ShoppingCarts" id="shoppingCartForm" type="insert"}}
Obviously you don't want totalPrice to be an item on the form for the user to fill on their own. systemGeneratedInfo could be an object that your code generates based on the form values, but which doesn't appear on the form itself.
You could put totalPrice into a hidden form element but that seems sketchy. You really wouldn't want to do that with systemGeneratedInfo.
What other strategies would there be for tackling items on the object that don't show up on the form, but which still allow the form shown on the front end to be completely validated?
You have to make use of the schema field of the quickForm or autoForm. Then you create Template helpers to pass the schema to the form (or if your schemas are available globally you can just pass Schemas.someSchema to the form).
You can either define completely new schemas just for minor form functionality tweaks, which in my mind is overkill if you have a giant nested schema and you just want to omit a couple of fields or...
You can just import the original schema into your template.js and then do an EJSON.clone on it and modify the fields and attributes locally in the helper (or elsewhere) before you pass it to the template.
// Profile.js
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { AutoForm } from 'meteor/aldeed:autoform';
import { EJSON } from 'meteor/ejson';
import { Schema } from '../../../api/profiles/profiles.js';
Template.profile.helpers({
profileSchema: function() {
let userSchemaForAutoForm = EJSON.clone(Schema.User);
userSchemaForAutoForm._schema.emails.optional = true;
return userSchemaForAutoForm;
}
});
// Profile.html
{{#autoForm id="profileEditForm" collection="Meteor.users" schema=profileSchema doc=currentUser type="update"}}

Use Flow Router Param in Autoform

Friends,
I'm working on my first app in Meteor and hitting my head against the wall on something...
I have a scenario similar to a blog + comments situation where I have one collection (call it 'posts') and want to associate documents from another collection (call it 'comments').
The best way I know to pass the post._id to the comments as a "postId" field is to use the Flow Router params, since the form is on the 'post/:id' view.
But for the life of me, I cannot figure out how to get "var postId = FlowRouter.getParam('postId');" to pass to Autoform so it populates. I've tried adding it as a function in the schema, as a hook, and as a hidden field in the form on the page (obviously don't want to go that route).
Autoform is amazing and I want to use it, but may have to wire it up the hard way if I can't get this darn value to populate.
Any ideas? I've been hitting my head against the wall on this for a couple of days now.
Thanks!
First, just so we're on the same page, if you have your route is set up like this:
FlowRouter.route('/blog/:postId', {
action: function (params, queryParams) {
FlowLayout.render('layout', { body: 'postTemplate' });
},
});
You are able to call FlowRouter.getParam('postId') from inside the AutoForm hook
You'll need to use an AutoForm hook and have a complete schema. I'm using the package aldeed:collection2 for the schema set up. The postId field must be explicity declared. This code is running on both server and client.
Comments = new Mongo.Collection("comments");
Comments.attachSchema(new SimpleSchema({
comment: {
type: String,
label: "Comment"
},
postId: {
type: String
}
}));
Setting your form up like this is not what you want:
{{> quickForm collection="Comments" id="commentForm" type="insert"}}
That's no good because it will show the postId field in the HTML output. We don't want that, so you have to fully define the form like this:
{{#autoForm collection="Comments" id="commentForm" type="insert"}}
<fieldset>
{{> afQuickField name='comment' rows=6}}
</fieldset>
<button type="submit" class="btn btn-primary">Insert</button>
{{/autoForm}}
Then add the AutoForm hook. This code is running on the client.
var commentHooks = {
before: {
insert: function(doc){
var postId = FlowRouter.getParam('postId');
doc.postId = postId;
return doc;
}
}
};
AutoForm.addHooks(['commentForm'],commentHooks);
Make sure you have your allow/deny rules set up, and it should be working fine.
I was struggling with this same use case as well, and I found this on the Meteor forums: https://forums.meteor.com/t/use-flow-router-param-in-autoform/14433/2
If you're using a schema to build your form (either with the autoform or quickform tags) then you can put it right in there.
For example:
campaignId: {
type: String,
autoform: {
value: function() {
return FlowRouter.getParam('campaignId');
},
type: "hidden"
}
},

autoform array display no field (initialCount)

I have an autoform containing an array of Objects and and Array of Strings:
# Schema
misc:
type: Array
label: "Something"
optional: true
"misc.$":
type: String
optional: true
initially i want no form to be displayed. Just the "+"-button. I use this in my template:
+autoForm collection="Collections.UserProfiles" id="updateProfileForm" type="update" doc=this class="form-horizontal"
+afQuickField name="misc" template="bootstrap3-horizontal" initialCount=0
i already tried to use initialCount = 0 in the Schema as well.
Ok, I just found out how it works. Sorry for asking, but maybe someone has the same Question. Just specify you schema like this. It works for arrays of objects as well.
misc:
type: Array
label: "Something"
optional: true
autoform:
initialCount: 0
"misc.$":
type: String
optional: true
still i dont know why i didnt work to set it in the template. Because thats the ways it is explained in the autoform documentation.

Meteor autoform Form hidden fields not rendering defaultValue and not saving

I have two hidden fields in my autoform Schema defined as shown below. I wish to save those two fields with other fields while not showing them to the app user. But I noticed from the autoform rendered html that the two hidden fields have no value, also they don't save with other fields to DB. Not sure what I might be missing / wrong here? Thanks for your help
Invoice = new SimpleSchema({
clientid: {
type: String,
optional: true
},
total: {
type: String,
label: 'Total Amount',
optional: true
},
tax: {
type: String,
label: 'Taxes',
optional: true
},
category: {
type: String,
optional: true,
autoform: {
type: "hidden",
label: false
},
defaultValue: 'Test Category'
}
});
{{> quickForm id="invoiceForm" buttonContent="Insert" buttonClasses="btn btn-primary btn-sm" schema=Invoice type="method" meteormethod="saveInvoice"}}
I don't think that you can have a field in your aldeed Schema that will render/ get saved in the form as a hidden field. So I suggest you pass the data (which you originally wanted to pass a a hidden field) though Sessions.
For example, if you are using autoform >> meteormethod to save the form, then you can save the session content within the server method. If you are not using a method, then you might want to pass the hidden data through Autoform.hooks >> onSubmit
In my opinion it's best to keep the logic related to the form to the quickform template, for the case you would reuse your schema in another form, for instance.
I'd recommend you to do the following:
...
},
category: {
type: String,
optional: true,
defaultValue: 'Test Category'
}
...
And use the omitFields clause (note you can specify multiple fields to be omitted separating them by comma):
{{> quickForm id="invoiceForm" buttonContent="Insert" buttonClasses="btn btn-primary btn-sm" schema=Invoice type="method" meteormethod="saveInvoice" omitFields="category, foo, bar, ..."}}
I've noted you are using method as the form type. If you are manually setting a method for saving your data, you might consider specify default and auto values inside the method itself. It will give you more freedom and control over your data.
Have you tried not making the category field optional? There seems to be a conceptual problem between having a defaultValue and having the field as optional.

When using Meteorjs' autoform, can I set a field allowing the user to take a photo?

In the schema declaration I have:
CollectionName.attachSchema(new SimpleSchema({
issue: {
type: String,
label: "Describe the issue you noticed",
max:256
},
location: {
label: "Place a marker on your approximate location",
type: String,
autoform: {
type: 'map',
afFieldInput: {
type: 'map',
autolocate: true,
zoom:16
}
}
}
I'd like to allow a user to take a picture on this insert form
{{> quickForm collection="CollectionName" id="inserttoCollection" type="insert"}}
I'd like to be able to let an individual not only document the location of an issue but take a picture of what issue was noticed.
My question: How do I set up a field properly so that it allows a user to take and upload a photo.
This is one of the areas where Meteor shines - isomorphic APIs that work across desktop and mobile browsers.
You'll want to meteor add mdg:camera, add a button to your form, and set its click handler to run MeteorCamera.getPicture().
Read more at https://github.com/meteor/mobile-packages/tree/master/packages/mdg:camera

Resources