Meteor : Fundamental Database Strategy Scenario - javascript

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.

Related

Menu to filter results in Flask

I'm rather new to programming and super new to Flask. I'm implementing an html page which has a few filters on the left and it shows the results on the right.
For example a filter might be "2 people room". Selecting it, it would show only 2 people rooms in the div on the right.
All my data is in a DB.
What's the best way to implement it?
I'm thinking of this way:
- Implement onclick JS function that, when clicking on 2people room filter, it would select a subset of the data (only the 2 people rooms) and then create html for all that data (in Jinja2).
Is here a better way to do so?
thanks
You could use a HTML checkbox.
You could then have some JavaScript that displays the results based on which checkboxes are checked or not.
EDIT
I have quickly made a form here, using pure HTML/JavaScript. What you could do is make a GET request to your flask server using the contents of array. Or just make a basic SQL query to your database: SELECT houses FROM table WHERE rooms=array. ( That's not a valid SQL query, you will have to pass in the numbers properly)
<!DOCTYPE html>
<html>
<body>
<p>Filter Menu</p>
<form action="/action_page.php">
<input type="checkbox" name="room" value="0">Studio<br>
<input type="checkbox" name="room" value="1">One bed<br>
<br>
<input type="button" onclick="myFunction()" value="update filter">
</form>
<script>
function myFunction() {
var form = document.forms[0];
var array = [];
var i;
for (i = 0; i < form.length; i++) {
if (form[i].checked) {
array.push(form[i].value);
}
}
console.log(array)
// Make an SQL query with array
}
</script>
</body>
</html>

Can't set headers after they are sent. in NodeJS using HBS

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.

Multiply 2 input values and display on input textbox using Meteor template helper

I'm developing restaurant management system using MeteorJS. What I try to accomplish here is when I type in some number on "Quantity" column it multiples itself with the price in "Price" column, then displays total sales inside textbox in "Total" column. I'm aware that there're several solutions out there but I wonder if this can be done using Meteor template helpers.
Screenshot
Yes it can, Meteor template is reactive so you simply need to do something like:
<template name="costCalcualtor">
<input id="quantity">
<p id="price">$10</p>
<p>It'd be ${{totalCost}}.</p>
</template>
in your html, and in your JS, simply makes a Template.costCalcualtor event that fires every time user finish typing in the input of "quantity" id, parse the innerHTML as integer, multiply it by the price (another integer obtained by parsing innerHTML of the p of "price" id), Session.set('price',finalValue), then have totalCost as a Template.costCalcualtor helper function that returns a new value based on Session.get("price").
Update:
don't just return a variable in the keyup event, you should use Session.set("total", price*quantity); in the end, and the line var total = parseInt($('total').val(price * quantity)); doesn't really do anything.
then you need {{totalCost}} in the template. and define a helper to retrieve the value of the session variable "total": Session.get("total").
Here is a walk-through to demonstrate what I mean:
in your .js fileh:
if (Meteor.isClient) {
// counter starts at 0
Session.setDefault('counter', 0);
Template.salesAdd.helpers({
total: function(){
return Session.get("total")
}
});
Template.salesAdd.events({ 'keyup #meow': function() {
var quantity = parseInt($('#meow').val());
console.log(quantity);
Session.set("total", quantity); } })
}
in your .html file:
<head>
<title>meow</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> salesAdd}}
</body>
<template name="salesAdd">
<input id="meow">
<p> What you've typed: {{total}}</p>
</template>
run it & see the number changes as you type in <input>.
Meteor is very a powerful tool developed by great people, and what is nice about it is that it is easy-to-learn and it has good documentation, so I suggest you to go through the basic docs and if possible, the full api.

Meteor Newbie query about best practice

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.

How to collect form data in multiple steps and summarize it

Problem
I have a form which is divided into five different sections. Find the Image below. When a person comes on this page I direct him/her directly to the Summary stage with pre-populated data which is working fine. Where the problem comes is there's an option for the user to go n edit this form by clicking on prev button. After the user changes the value in the previous stages and comes back to the summary stage it still shows them the default information which came through the pre-populated data but when a user submit form it submits the correct info with new edited data.
Is there any way I can refresh or reload it? I'm using the below code to display this summary.
Code
//Button to reach the summary stage
<button type="button" class="next" id="summary" onclick="loadnext(4,5);"><img src="images/next.jpg" alt="" /> </button>
//Display
<tr>
<td>Team Name</td>
<td id='t_name_SUM'></td>
</tr>
<tr>
<td>Team Visibility</td>
<td id='t_visibility_SUM'></td>
</tr>
To better support my comment I'm writing this answer.
What you need to do is provide a mechanism to collect data step by step. Copying HTML into other elements is not a very flexible way to do that.
I created a jsfiddle to demonstrate the idea. It's far from perfect but at this stage it works without making things to complicated.
The basic idea is to have an object to control the flow of the views(steps) the user needs to handle. Each view has a controller associated with it to handle the data.
The views.
<div id="step1" class="view">
<h3>Step #1</h3>
<input type="text" name="name" value="" />
</div>
<div id="step2" class="view">
<h3>Step #2</h3>
<input type="text" name="title" value="" />
</div>
<div id="step3" class="view">
<h3>Step #3</h3>
<input type="text" name="message" value="" />
</div>
The object controlling the flow (only showing the most relevant parts).
var flow = {
...
settings:{}, // settings to save
routes: [
{controller:Step1Ctrl, element:'#step1'},
{controller:Step2Ctrl, element:'#step2'},
{controller:Step3Ctrl, element:'#step3'}
],
...
show: function (index) {
var route = this.routes[index];
if (this.currentController) {
this.currentController.commit();
}
this.index = index;
this.currentController = new route.controller(
this.settings,
route.element
);
}
};
Every time a new view is shown the current controller commits the changes to settings and a new controller is created for the current view.
A simple controller can look like this.
function Step1Ctrl(settings, element) {
var $e = $(element).find('input[name="name"]');
$e.val(settings.name); //set the initial value
this.commit = function () {
settings.name = $e.val(); //save
};
}
Since every controller now commits it's changes to settings it easy to represent that data in any way you like. The fiddle just alerted the collected data but you can easily create another view and another controller to display thse settings.
Also, because every controller has access to the settings it can act upon values that are already in there or check if a combination of settings is even possible or not.

Categories

Resources