I get the following error while trying to render my page
Can't set headers after they are sent.
Below is what I am trying to do
res.render('information', {
name: rows[i].name,
boxId: rows[i].box
});
console.log(rows[i].name);
It prints out the right information in the console, so i know that this is correct, but getting that information render at information page is an issue
{{#each items}}
<form method="post" action="">
<input type="hidden" value="{{BoxId}}">
<button type="submit">{{name}}</button>
</form>
{{/each}}
Essentially on that page I am trying to run a for loop, where a new button form must be generated with each item found in the database. If there 5 items with name, and box value, then this should produce 5 times with their respective value and name set.
However, this is a secondary problem, because even doing <h3> {{name}} </h3> it doesnt work and i get the set headers problem.
Any help would be appreciated.
Template language being used:
http://handlebarsjs.com/
I'm not sure how you have this setup, but is the res.render itself in a for loop? If so, pass the entire data set to the template, and loop through in the template itself, something like:
var data = {
rows: rows
}
res.render('information', data);
And in the template:
{{#each rows}}
{{this.propName}}
{{/each}}
If you have nested data, you can have nested {{#each}} statements as well.
Related
I have lots of models and show them in tables. When user needs to do something with several models, we need to give him ability to choose rows.
How can I implement it with checkboxes? Of course I don't want to create special field on my models for every table.
This is simple example.
https://ember-twiddle.com/0b8f429f6ad3e0572438
My tries were:
{{input type='checkbox' checked=model.someNotExistedField}}
But in this case input just doesnt work.
And:
<input type="checkbox" {{action marked model}} checked={{in-arr record selectedItems}} />
In second example I've tried to keep selected ids in an array on context. But id doesnt work too.
There are a few steps to solving this problem, which you have not shown in your code examples.
you dont need to worry about binding a checked value on the checkbox.. it can manage its own internal state, and you can take advantage of it when selecting an item... a native <input> should be fine
<input type="checkbox">
You will need an action (preferably a closure action) that handles what to do when a record is selected
onchange={{action (action "valueHasChanged" item) value="target.checked"}}
You will need an array to store the "selected items"
this.selectedItems = [];
I put together a twiddle as one example of how these pieces fit together.
(This answer should be valid with ember version 1.13.0 and up)
I'am guessing your model is an array of rows.
So try adding a chked (boolean) property to the model structure so you now have one for each row and bind it to the respective checkbox.
I finished with such technic:
components/action-based-checkbox.hbs
{{#if checked}}
<input type="checkbox" {{action changed}} checked="checked" />
{{else}}
<input type="checkbox" {{action changed}} />
{{/if}}
In context we have array with selected items, for instance "selectedItems"
In context we have an action, that manages array
//2 and 3 steps example
actions:{
marked(id){
this.selectedItems.push(id);
var uniq = this.selectedItems.uniq();
this.set('selectedItems', uniq);
},
selectedItems:[],
4.next I put the component to my cell
{{inputs/action-based-checkbox changed=(action marked record.id) checked=(in-arr record.id selectedItems)}}
in-arr my "in_array?" helper, ember 2.3
Learning Meteor, which is great, but I'm struggling a bit with "best practice".
For example, I'm building a small example quiz, which looks like:
Question : 1 + 1 = ? ---> Dropdown box [1, 2, 3]
Question : 1 + 0 = ? ---> Dropdown box [1, 2, 3]
Question : 1 - 1 = ? ---> Dropdown box [1, 2, 3]
Question : 2 + 1 = ? ---> Dropdown box [1, 2, 3]
Then, at the bottom is a Button that says "Score Me".
When that button is pressed, it should go through each question and put a little "Correct" or "Wrong" next to the dropdown box.
All of this looks something like:
<template name="questions">
<div class="jumbotron">
{{#each questions}}
<span class="lead">{{question}} </span>
<select class="answerDropDown">
{{#each answer}}
<option value={{this}}>{{this}}</option>
{{/each}}
</select>
<span id="correctornot">{{correctornot}}</span>
{{/each}}
</div>
</template>
I'm pulling the data from the DB using:
Questions = new Mongo.Collection("questions");
And everything is working fine. I've plugged in events and it reacts well, etc... etc...
What I can't do easily is see how to make correctornot work. Well... I say that, but what I mean is nothing really makes sense.
I would imagine when I got the data:
Template.questions.helpers({
questions: function() {
return Questions.find({});
}
I would want to add extra data to each question, but this isn't meant to be saved in the database.
I guess I'm just looking for the correct way to go about it. Even the answers aren't saved anywhere, so when I check to see if it's correct, I'm currently looking at Session variables that are changed on the dropdown select event.
Anyway, all advice welcome.
Cheers.
What you want is benefit from Blaze's reactivity without persisting information in your database. The answer? Reactive client-side values! They come in different form:
Session variables
Reactive variables
Client-side collections
... and many more provided by atmosphere packages
When evaluated in designated contexts (such as helpers or Tracker.autorun), the code included in said context will be ran again every time the value in the reactive variable changes, hence, in the case of helpers, triggering changes in your template.
Example: using Session
Here, we will see the easier way to achieve this, using the built-in Session object. Let's assume your questions template is included in a template called form which contains your submit button:
<template name="form">
{{> questions}}
<form id="form">
<input type="submit" value="Score me" />
</form>
</template>
First, we must set a submitted session variable to false when the form template gets rendered.
Template.form.onRendered(function () {
Session.set('submitted', false);
});
Then, catch the form submission event, and instead of submitting, we're going to set our new submitted reactive variable to true.
Template.form.events({
'submit #form': function (e, t) {
e.preventDefault();
// do some prior validation here if needed
Session.set('submitted', true);
}
});
Now, all we need to do is to check in a submitted template helper whether submitted is set to true or false. If it is true, we then proceed to display the result of the correctornot helper, which fetches the value selected in the dropdown and compares it to the correct answer for the question stored in the current data context (the each loop). Assuming this answer is stored in a correctAnswer property of your question:
Template.questions.helpers({
'questions': function() {
return Questions.find({});
},
'submitted': function () {
return Session.get('submitted');
},
'correctornot': function () {
var userResponse = $('#'+this._id+'.answerDropDown').val();
return (this.correctAnswer == userResponse);
}
});
And here is our slightly enhanced questions template:
<template name="questions">
<div class="jumbotron">
{{#each questions}}
<span class="lead">{{question}} </span>
<select id="{{_id}}" class="answerDropDown">
{{#each answer}}
<option value={{this}}>{{this}}</option>
{{/each}}
</select>
{{#if submitted}}
<span id="correctornot">{{correctornot}}</span>
{{/if}}
{{/each}}
</div>
</template>
As you can see, with very little code, you can achieve a nice reactive behavior.
What if I don't want to pollute Session with a pointless flag?
Then, you can look into reactive variables. They're easy to implement once you have the logic in your mind. The little tricky part in your case is that you seem to use nested templates: the submit button triggering the reactive change and the questions list reacting to it are not in the same template. So you will need to navigate between template instances to access the submitted reactive variable. Look at this answer for clues on this subject.
The Html Page Looks like this :
index.html
<head>
<title>MP3</title>
</head>
<body>
{{> download}}
<div class="container">
<ul>
{{#each songs}} {{> okay}} {{/each}}
</ul>
</div>
</body>
<template name="download">
<input type="text" id="songname">
<button id="hitit">Submit</button>
</template>
<template name="okay">
<form action="{{linksong}}">
<li><input type="submit" value="Download {{kbps}} kbps" id = "{{kbps}}"></li></form>
</template>
Now, from the input button, I use this code to add it to minimongo collecction :
document.addEventListener('DOMContentLoaded', function() {
var inputterm = document.getElementById("songname");
var submitButton = document.getElementById("hitit");
submitButton.addEventListener('click', function() {
SearchTerm.insert({
sub: inputterm.value
});
}, false);
});
Then I have to access the term I added to the database, query it, and add the result to a new database.
Q1 : I don't know how to query the database to extract the same term.
But, before that, a fundamental question arises :
Let's say there are ten users using the app at the same time from different locatons, and they hit submit at different times but before anyone has got a response.
THe query is added to the same database for all the users. SO, the one who fires the last query will get the correct result and the rest will be like : "What the hell?"
All I'm trying to say, if this app is going to have thousand users, is it Viable to create seperate databases for all of them, and if yes, then how can it be implemented?
And Is there any other way like Sessions, publish and subscribe, and do they fit the above scenario ?
Plus it is a download song sort of a website, so there is no point asking the user to login or whatever.
I have this Meteor template:
<template name="personalDetailsForm">
{{> quickForm collection="PersonalDetails" id="personalDetailsForm" type="insert"}}
{{> quickForm collection="PersonalDetails" doc=editingDoc id="personalDetailsForm" type="update"}}
</template>
The forms are displayed as I expect, however I just want one form. A blank form for when there is no data which does an insert when the form is submitted. Then when the form is reloaded the data previously submitted is shown on the form. If the form is then submitted again any data that has changed will be updated.
Currently the insert form is displaying and underneath it the update form is displaying, with the data that has been previously inserted. Trying to update the data on the second form doesn't work, instead it inserts a new record. This I imagine could be because the form ids are the same.
Ideally I would like to do something like this:
<body>
{{#if PersonalDetails}}
{{> personalDetailsFormUpdate}}
{{ else }}
{{> personalDetailsFormInsert}}
{{/if}}
</body>
<template name="personalDetailsFormInsert">
{{> quickForm collection="PersonalDetails" id="personalDetailsFormInsert" type="insert"}}
</template>
<template name="personalDetailsFormUpdate">
{{> quickForm collection="PersonalDetails" doc=editingDoc id="personalDetailsFormUpdate" type="update"}}
</template>
I think this part of the documentation is what I'm looking for:
Can I reuse the same quickForm or autoForm for both inserts and updates?
Yes. Your code that flips between states should do the following in this order:
Change the type attribute's value to "insert" or "update" as appropriate, probably by updating a reactive variable.
Change the doc attribute's value to the correct document for an update or to null (or a document containing default values) for an insert, probably by updating a reactive variable.
Call AutoForm.resetForm(formId). This will clear any existing validation errors for the form.
Can anyone provide an example of this?
The question was asked some time ago, but I had the same issue and just solved it.
It is quite easy:
Get the context data as usual. E.g. with iron-router, build a route like:
Router.route('Options', {
path: 'options',
data: function() {
var options = Options.findOne({owner: Meteor.userId()});
return options;
}
});
Build a new helper, that checks if the context data (this in the helper) is empty or not (example is for a global helper that works in every template):
UI.registerHelper("formType", function(){
if(_.isEmpty(this)) {
return 'insert'
} else {
return 'update';
}
});
Setup the template with the new helper:
<template name="Options">
<h1>Options</h1>
{{> quickForm collection="Options" doc=this id="optionsForm" type=formType omitFields="owner"}}
</template>
Everything should work now. If the database doesn't give a value back, the form will automatically switch to insert. So in my example, if you open the form the first time, it will use insert. The second time, it will use update.
thanks #peXd. this was very helpful. however I had an additional required field in my schema which was blocking the insert and it was silently failing to insert and since i stumbled into this solution through 8 trap doors i thought i'd post it in case it helps someone else.
i found this recommendation from aldeed [https://github.com/aldeed/meteor-autoform/issues/199] to use this error hook in client code:
AutoForm.addHooks(null, {
onError: function (name, error, template) {
console.log(name + " error:", error);
}
});
however this also failed with me saying AutoForm was not defined. this was odd to me because aldeed:autoform was being pulled into the project as a dependency. but just to double check i did meteor add aldeed:autoform to pull it in directly and suddenly AutoForm was available to add the hook to.
I'm having some trouble understanding how ko.mapping.fromJS and ko.mapping.toJS work.
Here the explanation of my problem simplified:
I have a Risk Array object coming from the Server, that Risk array has a Places array.
For some strange reason, after calling the ko.mapping.FromJS my child Places array gets cleared or hidden, so my template can't access its contents... I found that by using ko.mapping.ToJS I can get access to Places contents but by doing this It doesn't seem to refresh my template after adding an Item!
I'm trying to build a very simple grid where I can add places to the first Risk in the array for simplification purposes:
var FromServer = {"Risk":[{"SourceKey":0,"Places":{"Place":[{"SourceKey":1}]}}]}
var viewModel =
{
places : ko.mapping.fromJS(FromServer.Risk[0].Places.Place),
addPlace : function()
{
alert('Entering add place, places count:' + this.places.length);
this.places.push({SourceKey:"New SK"});
}
}
//If I leave this line it will update list but not refresh template
//If I comment it out it will show my Places array as empty!!!
viewModel = ko.mapping.toJS(viewModel)
ko.applyBindings(viewModel);
Here my sample HTML code for my grid:
<p>You have asked for <span data-bind="text: places.length"> </span> place(s)</p>
<table data-bind="visible: places.length > 0">
<thead>
<tr>
<th>SourceKey</th>
</tr>
</thead>
<tbody data-bind='template: { name: "placeRowTemplate", foreach: places}'></tbody>
</table>
<button data-bind="click: addPlace">Add Place</button>
<script type="text/html" id="placeRowTemplate">
<tr>
<td><input class="required" data-bind="value: $data.SourceKey, uniqueName: true"/></td>
</tr>
</script>
Here is my jsFiddle: jsFiddle Sample
My question is: why do I have to unwrap my viewModel with ko.mapping.ToJS so I can manipulate my child array?, and how can I have my template refreshing in this scenario?
Please help!
You had a few things wrong with your code. New JSFiddle here:
http://jsfiddle.net/ueGAA/4/
You needed to create an observable array for the places array, otherwise knockout will not know when it has been updated. The method call is
ko.observableArray(arrayVar)
You do no want to call toJS on your view model. That unwraps all of the observables and makes Knockout not capable of updating your bindings
When referencing an observable array, you need to use parens: ie. viewModel.places().length.
In your FromServer object your Place object contained an array with the object {"SourceKey": 1} inside of it. I assumed you intended for the place object to just have a simple property called SourceKey