I am new to meteor.Iam using meteor aldeed autoform and collection2 packages in my app.here is my client js file.
Schema = {};
Schema.dc_address = new SimpleSchema({
'dataCenterName': {
type: String,
index: 1,
label:'Name of the Provider',
regEx: /^[a-zA-Z\s]+$/
},
'address1': {
type: String,
index: 1,
label:'Address Line 1',
regEx: /^[a-zA-Z0-9\s]+$/
},
'address2': {
type: String,
index: 1,
label:'Address Line 2',
regEx: /^[a-zA-Z0-9\s]+$/
},
});
Template.dataCenters.helpers({//dataCenters is my main template
steps: function() {
return [{
id: 'dc_address',
title: 'Name & Address',
template: 'dc_address',
formId: 'dc_address_form',
onSubmit: function(data, wizard) {
var params=_.extend(wizard.mergedData(), data);
alert(params);
var jsonrpc = new $.JsonRpcClient({ ajaxUrl: 'http://172.16.4.190:8384' });
jsonrpc.call(
'dataCenterCreate', params,
function(result) {alert('Pizzeria answered: ' + $.toJSON(result)); },
function(error) { console.log('There was an error', $.toJSON(error)); }
);
}
}];
}
});
here is my html page
<template name="dc_address">
<div class="form-wrapper">
{{#autoForm doc=this.data id="dc_address_form" schema=Schema.dc_address }}
<div class="col-md-12">
{{> afQuickField name="dataCenterName" placeholder="Enter DataCenter Name"}}
</div>
<table>
<tr>
<td class="col-md-6">
{{> afQuickField name="address1" placeholder="#7 4th cross"}}
</td>
<div class="col-md-1"></div>
<td class="col-md-6">
{{> afQuickField name="address2" placeholder="ITPL-banglore"}}
</td>
</tr>
<button type="submit" class="btn btn-success btn-md pull-right">Next</button>
{{/autoForm}}
</div>
</template>
That works pretty well although - it's CLIENT side submit => it is not secure.
How do I implement it is in server side?
For security you should remove autopublish and insecure packages. Once you do this inserting anything into the databases will throw an error. Try Posts.insert({}) in the console to see the errors appear.
You get around this by adding allow and deny rules on your server (see the meteor docs for more on allow/deny rules). You can also use meteor methods using: Meteor.call(...) to insert docs into the database without having any allow rules set up. You'd have to do your own checks within the meteor method in this case.
Related
Objective: I have a form interface that is being loaded with an object's current data for editing. The user opens this modal with the form that is loaded with the current info so they an either edit it or leave it
Currently working: The form loads with the data from my three objects (details, editSubEvents, instructions) and shows properly without issue
My problem: When I edit the fields and hit submit, I'm only currently dumping the submitted data object to make sure I have what I need. I get the eventID fine becasue it won't change and I get it from the original object. However, I need to store the new title, instruction, and subEvents (as an array) in order to submit them because they're obviously different from the origin ones
How can I properly store the new info from these input fields, including storing the new subEvent title and instructions as an array?
<div class="modal-body">
<div class="form-group row" v-for="detail in details">
<p class="modal-title">Title</p>
<input v-model="detail.title" type="text" class="form-control" id="EventTitle" name="EventTitle">
</div>
<div class="form-group row" v-for="subEvent in editSubEvents">
<p class="modal-title">SubEvent Title</p>
<input v-model="subEvent.title" type="text" class="form-control" id="newSubTitle" name="newSubTitle">
<p class="modal-title">SubEvent Instructions</p>
<textarea v-model="subEvent.instructions" type="text" class="form-control" id="newSubInstructions" name="newSubInstructions"></textarea>
</div>
</div>
data() {
return {
details: [],
instructions:[],
editSubEvents:[],
}
},
methods: {
updateEvent() {
let data = {
EventID: this.details[0].event_id,
title:
origin:
instructions:
subEvents: //needs to be an array
};
console.dir(data);
}
}
All of the properties of your data object can be bound to the UI elements (and most of them are, going by your template example code). The properties of the data object are accessible through the Vue component's this.
new Vue({
el: '#vueApp',
data() {
return {
details: [],
instructions:[],
editSubEvents:[],
}
},
methods: {
updateEvent() {
const data = {
EventID: this.details[0].event_id,
title: this.details[0].title,
origin: this.details[0].origin,
instructions: this.instructions,
subEvents: this.subEvents,
};
console.dir(data);
}
}
}
I am new to Javascript and Meteor and having some trouble getting the Meteor autocomplete package from Mizzau to work correctly. I can get the form to autocomplete just fine, but having trouble getting it to filter my todos. The end result I am hoping for is to enter in a todo into the autocomplete and have it filter the subscription, I would also settle for search and going from there. I will also say my initial state is the list returns 0 todos (none are displayed) I feel like I may be close. A good part of my code came from this: Meteor - autocomplete with "distinct" feature?
T
Does it have something to do with my subscription?
Here is my server side publish call:
Meteor.publish("todosAuto", function(selector, options) {
Autocomplete.publishCursor(Todos.find(selector, options), this);
this.ready();
});
My client side subscription:
Meteor.subscribe('todosAuto');
The relevant part of my template:
<div class="container todoFormSec">
<div class="col-md-4">
{{> inputAutocomplete settings=settings id="msg" class="form-control" placeholder="Search..."}}
</div>
<div class="row">
<div class="col-md-5 pull-right">
<h1 class="todocountstyle text-right">You Have {{ todoCount }} Todos</h1>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="todos">
{{ #each todosAuto }}
{{ >todo }}
{{ /each }}
</div>
</div>
</div>
</div>
And my settings:
Template.home.helpers({
todos: function() {
return Todos.find();
},
todoCount: function() {
return Todos.find({userid: Meteor.userId()}).count();
},
settings: function() {
return {
position: "top",
limit: 5,
rules: [
{
token: '#',
collection: 'Todos',
field: "title",
subscription: 'todosAuto',
template: Template.titlePill
},
{
token: '#',
collection: 'Todos',
field: "categories",
options: '',
subscription: 'todosAuto',
matchAll: true,
template: Template.dataPiece
}
]
};
}
});
Template.home.events({ // listen for selection and subscribe
"autocompleteselect input": function(event, template, doc) {
Meteor.subscribe("todosAuto", doc.title);
}
});
In the past I tried to use this autocomplete package you are having trouble with. I found it just wasn't high fidelity enough for my needs. Therefore I recommend Twitter typeahead and bloodhound to you. I am very happy with the following packages ajduke:bootstrap-tokenfield in combination with sergeyt:typeahead
The time investment is well worth it. See my previous posting for examples. Here are more examples.
If the above is too complicated, try jeremy:selectize. Point is that there are plenty of better packages out there.
After I upgraded meteor from (1.0.5 to 1.1.2) When I tried to upload files using cfs:autoform it refused to hold files. Like I would chose a file and click submit, but it would throw an error and tell me the file does not exist (The field was required). Is this a none bug or am I doing something wrong? I have put my code below:
<template name="school_create">
<div class="header">School Create</div>
{{#autoForm collection="Schools" id="school_create" type="insert"}}
<fieldset>
<legend>Add a School</legend>
<div style="float:left">
<div class="textField">
{{> afQuickField name='name'}}
</div>
<div class="textField" style="margin-left:20px;">
{{> afQuickField name='sub_domain'}}
</div>
</div>
<div class="descriptionText">
{{> afQuickField name='image' type="cfs-file" collection="images"}}
</div>
<div class="textField" style="margin-left:20px;">
{{> afQuickField name="primary_color"}}
</div>
</fieldset>
<button type="submit" class="btn btn-primary">Add a School</button>
</template>
{{/autoForm}}
schools collection js
Schools = new Mongo.Collection("Schools");
//Defining the schema
Schools.attachSchema(new SimpleSchema({
name: {
type:String,
label: "Name",
max:200
}
user_id:{
type: String,
autoform: {
type: "hidden",
label: false
},
autoValue: function(){
if (this.isInsert) {
return Meteor.userId();
} else if (this.isUpsert) {
return {$setOnInsert: Meteor.userId()};
} else {
this.unset();
}
},
denyUpdate:true
},
image: {
type: String,
label: "Logo",
autoform: {
afFieldInput: {
type: "cfs-file",
collection: "images"
}
}
},
...
common.js
FS.debug = true; // enable CFS debug logging
// Image collection methods
Images = new FS.Collection("images", {
stores: [new FS.Store.FileSystem("images")]
});
Images.allow({
download: function () {
return true;
},
fetch: null
});
I have this quickForm:
{{> quickForm id="insertFixie" collection="Fixies" type="insert" doc=seedObject}}
Backed up by this schema:
Fixies = new Meteor.Collection('fixies');
Schema.Fixies = new SimpleSchema({
description: {
type: String,
label: "Description",
trim: true,
optional: true
},
cost: {
type: Number,
label: "Cost",
min: 0,
decimal: true
},
product_id: {
type: String,
autoform: {
omit: true
}
},
});
Fixies.attachSchema(Schema.Fixies);
and this seedObject method:
Template.insertFixie.helpers({
seedObject: function () {
console.log({product_id: this._id});
return {product_id: this._id};
}
});
When that console call directly above happens, it's correct and gives something to this effect:
Object {product_id: "1"}
But when I submit the form with something valid (like "stuff" and "100"), I get this error:
insert error:
Error: Product is required {invalidKeys: Array[1],
validationContext: SimpleSchemaValidationContext,
stack: (...),
message: "Product is required"}
stating that the product_id attribute is required and currently has a value of null.
What am I doing wrong? That product_id is a template dependent value, so something like "autoValue" in the schema doesn't seem like the best way to handle it.
The docs seem to clearly state that I'm using things correctly. From the description of the doc attribute of Auto Form:
For an insert form, you can also use this attribute to pass an object
that has default form values set (the same effect as setting a value
attribute on each field within the form).
And from the description of the value attribute of afFieldInput:
value: Set a specific, potentially reactive, value for the input. If
you have also provided a doc attribute on the autoForm or quickForm,
this value will override the value from the doc object.
What am I missing?
Edit
I added an autoValue field to my schema, just to see what pops up:
autoValue: function (doc) {
console.log(doc)
console.log(this.value)
return "1";
}
This allows the form to correctly submit, but with the incorrect hard-coded value of "1" rather than a useful value from the template. The two console logs show this:
:24 Object {description: "stuff", cost: 50}
:25 undefined
It seems my seedObject value isn't available to autoValue.
Do I have to hijack the onSubmit hooks? Do I have to have hidden form inputs with values supplied from the template? What's the fix here?
It turned out to be a hidden input.
I expanded my form to this:
{{#autoForm id="insertFixie" collection="Fixies" type="insert"}}
<fieldset>
{{> afFormGroup name="description" placeholder="schemaLabel" label=false}}
<div class="form-group{{#if afFieldIsInvalid name='cost'}} has-error{{/if}}">
<div class="input-group">
<div class="input-group-addon">$</div>
{{> afFieldInput name="cost" placeholder="schemaLabel" label=false}}
</div>
{{#if afFieldIsInvalid name="cost"}}
<span class="help-block">{{afFieldMessage name="cost"}}</span>
{{/if}}
</div>
{{> afFormGroup name="product_id" type="hidden" value=_id}}
</fieldset>
<button class="btn btn-primary" type="submit">Insert</button>
{{/autoForm}}
Adding an afFormGroup with type="hidden" did exactly the trick.
Although it still seems to me like the doc argument isn't living up to it's promises.
I've got an Ember.js app with this javascript:
var App = Ember.Application.create({
LOG_TRANSITIONS: false,
LOG_TRANSITIONS_INTERNAL: false,
LOG_VIEW_LOOKUPS: false,
});
App.Router.map(function() {
this.route('messageviewer', { path: '/message_viewer' });
});
App.Message = Ember.Object.extend({
message: {},
topic: '',
});
App.Message.reopenClass({
messages: {},
topics: [],
getAllMessagesList: function(){
var ret = [];
for(var i = 0; i < this.topics.length; i++){
ret = ret.concat(this.messages[this.topics[i]]);
}
return ret;
}.observes('App.Message.messages');
addMessage: function(message){
console.log(message);
if(!(message.topic in this.topics)){
this.topics.push(message.topic);
this.messages[message.topic] = [];
}
this.messages[message.topic].push(App.Message.create({
message: message,
topic: message.topic,
}));
},
});
App.MessageviewerRoute = Ember.Route.extend({
model: function(){
return App.Message.getAllMessagesList();
},
});
App.MessageviewerView = Ember.View.extend({
templateName: 'messageViewer',
didInsertElement: function(){
Ember.run.scheduleOnce('afterRender', this, fayeStartListening);
},
willDestroyElement: function(){
fayeStopListening();
},
});
Here's the template that goes with the view:
<div class="row">
<div id="filter-panel" class="col-md-3">
<h2>Topics</h2>
<div class="btn-group-vertical full-width" data-toggle="buttons">
<label class="btn btn-primary">
<input type="radio" name="topics">Test 1</input>
</label>
<label class="btn btn-primary">
<input type="radio" name="topics">Test 2</input>
</label>
</div>
{{#with content}}
{{#each}}
{{!-- Make a topic list for testing --}}
<h4>{{topic}}</h4>
{{/each}}
{{/with}}
</div>
</div>
There's also a Faye client running, and it's subscribed to a channel that gets quite a few messages/sec. In its subscription, it calls App.Message.addMessage(message); and I know this is working based on the log output in addMessage. Also, I've confirmed in the Ember Inspector that the model is being updated. However, the DOM is not changing. If I switch to a different route and come back, the list shows all the items gathered while the Faye client was listening. I'm not quite sure what I should do to get the list to update dynamically.
I did notice that if I do {{#each in content}} or {{#each in model.content}} instead of the {{#with}} block then I get an error "Cannot set property 'dataSourceBinding' of undefined". Also, I've seen people suggest using this.set(..., ...) but that won't work in my case because I'd have to call it from a static context so it's undefined.
Does anyone know how to convince Ember to update the DOM in real time?
Use pushObject or addObject instead of push, it's analogous to the setter for arrays.
Since you're trying to watch the messages object, you are watching whether the reference changes, not whether or not anything under it changed.
http://emberjs.com/api/classes/Ember.Observable.html#method_notifyPropertyChange