Backbone.js and node.js : how show my data in <select></select> html - node.js

hello i am newbie in node.js and backbone.js i need u help for my development programming..
my literature : http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/
i have code in :
node.js // mongodb database
server.js
app.get('/class',function(req, res) {
console.log('show all data in class');
db.collection('ak_classroom', function(err, collection) {
collection.find().toArray(function(err, items) {
res.send(items);
});
});
});
main.js
var AppRouter = Backbone.Router.extend({
routes: {
"class" : "show_class",
},
show_class: function(page) {
var p = page ? parseInt(page, 10) : 1;
var classList = new ClassCollection();
classList.fetch({success: function(){
$("#content").html(new classView({model: classList, page: p}).el);
}});
this.headerView.selectMenuItem('home-menu');
},
});
utils.loadTemplate(['show_class_View'], function() {
app = new AppRouter();
Backbone.history.start();
});
in models.js
//=== for get my link database mongodb get /class
window.class = Backbone.Model.extend({
urlRoot: "/class",
idAttribute: "_id",
//my default variable in databsae
defaults: {
_id: null,
sch_id : "",
cls_name: "",
cls_description: "",
cls_active: "",
}});
//get collection database
window.classCollection = Backbone.Collection.extend({
model: Class,
url: "/class" });
in classlist.js
window.classView = Backbone.View.extend({
initialize: function () {
this.render();
},
render: function () {
var class = this.model.models;
var len = class.length;
var startPos = (this.options.page - 1) * 100;
var endPos = Math.min(startPos + 100, len);
$(this.el).html('<table id="content"><thead><tr><th>ID School</th><th>Name class</th><th>Description</th></tr></thead></table>');
for (var i = startPos; i < endPos; i++) {
$('.content', this.el).append(new show_class_View({model: class[i]}).render().el);
}
return this;
}
});
window.show_class_View = Backbone.View.extend({
tagName: "tr",
initialize: function () {
this.model.bind("change", this.render, this);
this.model.bind("destroy", this.close, this);
},
render: function () {
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
show_class_View.html
<table width="200" border="1">
<tbody>
<tr>
<td><%= sch_id %></td>
<td><%= cls_name %></td>
<td><%= cls_description %></td>
<td><%= cls_active %></td>
</tr>
</tbody>
</table>
this scema is sucess but my question how create data for
<select name="cls_name" value="<%= cls_name %>">
<option><%= class[i].cls_name %></option>
</select>
where in select class name in array for select data ??
i am new in backbone.js so i dont know schema ?? please help i am confusion

My first guess would be that you need to have a proper underscore templating to make your select happen. Something like this:
<script type="text/template" id="rate_select_template">
<select id="rate-selector">
<% rates.each(function(rate) { %>
<option value="<%= rate.get('duration') %>"><%= rate.get('duration') %></option>
<% }); %>
</select>
</script>
You can see a working example here:
http://jsfiddle.net/ambiguous/AEqjn/
And the underscore template doc here: http://documentcloud.github.io/underscore/#template

Related

Updating array of objects in mongoose based off key in objects value

I have two ejs forms that when hit, make an HTTP post request to my /api/users/makePicks/:id route. This route hits my controller which updates the Users model in my mongodb with the NFL picks they submitted in the EJS form.
I need this route to create the picks object for each route if they do not exist for that particular week, and if they do exist it needs to update the picks that are already there. The picks are being stored in my User model in an array, this array contains objects for each weeks picks. Currently the code, with much help from Mohammed, is successfully pushing code to to array. But i cannot seem to figure out how to update the picks if an object with a key of that week exists.
My validation is finally working properly. What I mean is we are running a for loop on the picks array, it will console.log true if there is already a matching picks object with for that weeks picks, if the object with a first key value with the current weeks form doesn't exist, it will console.log false and push the new picks to the array.
The only part that isn't working is the if statement nested within my for loop, it is not updating the object if it already exists in the picks.array. But as I said, the validation is working correctly. I suspect the line of code
result.picks[i] = { [`week-${req.params.week}`]:req.body };
is for some reason not updating object with the updated req.body.
Controller
exports.makePicks = async (req, res, next) => {
const picks = req.body;
try {
let result = await User.findById(req.user._id);
if (result.picks.length > 0) {
for (let i = 0; i < result.picks.length; i++) {
if ((Object.keys(result.picks[i])[0] == [`week-${req.params.week}`])) {
console.log(chalk.green("true"));
result.picks[i] = { [`week-${req.params.week}`]:req.body };
break;
} else {
console.log(chalk.red("false"));
result.picks.push({ [`week-${req.params.week}`]: picks });
break;
}
}
} else {
result.picks.push({ [`week-${req.params.week}`]: picks });
console.log(chalk.yellow('results.picks is empty'))
}
await result.save();
res.redirect("/api/dashboard");
} catch (error) {
console.log(error);
}
};
result.picks example structure
[{"week-1":
{"jojo-0":"ARI","jojo-1":"ARI","jojo-2":"ARI"}
},
{"week-2":
{"jojo-0":"ATL","jojo-1":"ATL","jojo-2":"BAL"}
},
{"week-3":
{"jojo-0":"ARI","jojo-1":"ARI","jojo-2":"ARI"}
}]
Router
router.route('/makePicks/:week')
.post(controller.makePicks);
EJS
<% const teamsArr = ['ARI', 'ATL', 'BAL', 'BUF', 'CAR', 'CHI', 'CIN', 'CLE', 'DAL', 'DEN', 'DET', 'GB', 'HOU', 'IND', 'JAX',
'KC', 'LAC', 'LAR', 'LV', 'MIA', 'MIN', 'NE', 'NO', 'NYG','NYJ', 'PHI', 'PIT', 'SEA', 'SF', 'TB', 'TEN', 'WAS' ] %>
<form class="mt-3 mb-3" method="POST" action="/api/users/makePicks/1">
<% for(i=0; i < user.bullets; i++){ %>
<div class="form-group">
<label for="<%= `${user.name}-${i}` %>">Make your pick for bullet <%= `${i}` %></label>
<select class="form-control" name="<%= `${user.name}-${i}` %>" id="<%= `${user.name}-${i}` %>">
<% teamsArr.forEach(team => { %>
<option value="<%= team %>"><%= team %></option>
<% }) %>
</select>
</div>
<% }; %>
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
<form class="mt-3 mb-3" method="POST" action="/api/users/makePicks/2">
<% for(i=0; i < user.bullets; i++){ %>
<div class="form-group">
<label for="<%= `${user.name}-${i}` %>">Make your pick for bullet <%= `${i}` %></label>
<select class="form-control" name="<%= `${user.name}-${i}` %>" id="<%= `${user.name}-${i}` %>">
<% teamsArr.forEach(team => { %>
<option value="<%= team %>"><%= team %></option>
<% }) %>
</select>
</div>
<% }; %>
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
you want to using $push and $set in one findByIdAndUpdate, that's impossible, I prefer use findById() and process and save() so just try
exports.makePicks = async (req, res, next) => {
const picks = req.body;
try {
//implementation business logic
let result = await User.findById(req.user._id)
if(result.picks && result.picks.length > 0){
result.picks.forEach(item =>{
if([`week-${req.params.week}`] in item){
item[`week-${req.params.week}`] = picks
}
else{
result.picks.push({ [`week-${req.params.week}`] : picks })
}
})
}
else{
result.picks.push({ [`week-${req.params.week}`] : picks })
}
await result.save()
res.redirect('/api/dashboard');
} catch (error) {
console.log(error)
}
}
note: don't use callback and async/await together
exports.makePicks = async (req, res, next) => {
const picks = req.body;
const { week } = req.params;
try {
let result = await User.findById(req.user._id);
const data = { [`week-${week}`]: picks };
const allPicks = [...result.picks];
if (allPicks.length > 0) {
// Search index of peek
const pickIndex = _.findIndex(allPicks, (pick) => {
return Object.keys(pick)[0] == `week-${week}`;
});
// If found, update it
if (pickIndex !== -1) {
console.log(chalk.green("true"));
allPicks[pickIndex] = data;
}
// Otherwise, push new pick
else {
console.log(chalk.red("false"));
allPicks.push(data);
}
} else {
allPicks.push(data);
console.log(chalk.yellow('results.picks is empty'))
}
result.picks = allPicks;
console.log('allPicks', allPicks);
await result.save();
res.redirect("/api/dashboard");
} catch (error) {
console.log(error);
}
};

How do I have a variable available to display on my success page, after adding items to a database via a /POST route?

I would like to display the doc.id variable of a successful /POST of data to a route, on the success page that the user will be redirected to afterward. I'm trying to work out how to carry the variable teamId through to the Handlebar template page success.hbs
I've tried making it a variable, and setting up a Handlebar helper to display it, but nothing is working.
/POST route redirecting to success.hbs:
app.post('/create', (req, res) => {
var players = [];
var playerObj = {};
for (let i = 1; i < 21; i++) {
var playerObj = { playerName: req.body[`player${i}Name`], playerNumber: req.body[`player${i}Number`], playerPosition: req.body[`player${i}Position`] };
if (req.body["player" + i + "Name"] === '') {
console.log("Empty player name detected, disregarding");
} else {
players.push(playerObj);
}
}
var newTeam = new Team({
// WEB SETUP BELOW
"team.teamRoster.teamCoach": req.body.coachName,
"team.shortTeamName": req.body.teamShortName,
"team.teamName": req.body.teamName,
"team.teamRoster.players": players
});
newTeam.save().then((doc) => {
var teamId = doc.id;
console.log(teamId);
res.render('success.hbs');
console.log("Team Added");
}, (e) => {
res.status(400).send(e);
});
});
/views/success.hbs
<div class="container-fluid" id="body">
<div class="container" id="page-header">
<h1><span id="headline">Team Added Succesfully</span></h1>
<hr>
<h3><span id="subheadline">Input the following address as a JSON Data Source within vMix.</span></h3>
<span id="content">
<div class="row">
<div class="container col-md-12">
{{{teamId}}}
</div>
</div>
</span>
</div>
<hr>
</div>
I'd like a Handlebar helper to get the doc.id value of the /POST request, and store it as teamId to display on the success page. It's finding nothing at the moment.
Any help is appreciated.
Node.js can pass variables to the handlebars-view like this:
newTeam.save().then((doc) => {
var teamId = doc.id;
console.log(teamId);
res.render('success.hbs', {
teamId
});
console.log("Team Added");
}, (e) => {
res.status(400).send(e);
});

Grouping my data in the view - nodejs

I grab some data from postgresql DB and want to display it in a view, simple enough as below
routes.js
app.get('/fixtures', async (req, res) => {
const fixtures = await queries.getFixtures();
res.render('fixtures', { fixtures });
});
fixtures returns
[ { id: 27,
home_team: 'Chelsea',
away_team: 'Liverpool',
league_name: 'English Premiership',
},
{ id: 25,
home_team: 'Man Utd',
away_team: 'Everton',
league_name: 'English Premiership',
},
{ id: 30,
home_team: 'Istanbul Basaksehir',
away_team: 'Akhisar Belediye',
league_name: 'Turkish Super Lig',
}
]
getFixtures();
async function getFixtures() {
let response;
try {
response = await pool.query('select * from fixtures ORDER BY league_name ASC');
} catch (e) {
console.error('Error Occurred', e);
}
return response.rows;
}
fixtures.ejs
<% fixtures.forEach((fixture) => { %>
<p><%=fixture.league_name %></p>
<p><%= fixture.home_team %> vs <%= fixture.away_team %> </p>
<% }) %>
So the above will output
English Premiership
Chelsea vs Liverpool
English Premiership
Man Utd v Everton
Turkish Super Lig
Istanbul Basaksehir vs Akhisar Belediye
However I would like to group my fixtures by league and would prefer to have the view output as
English Premiership
Chelsea vs Liverpool
Man Utd v Everton
Turkish Super Lig
Istanbul Basaksehir vs Akhisar Belediye
How do I go about achieving this? Is this something at DB query level or something I do in the view? (though probably not the best place to keep logic I guess)
Thanks
I'm not sure what tools/libs you are using but without depending on any libs/tools you can do it using vanilla JavaScript. For example, check the following code:
app.get('/fixtures', async (req, res) => {
const fixtures = await queries.getFixtures();
const grouped = groupByLeagueName(fixtures);
res.render('fixtures', { fixtures: grouped });
});
Then, implement the groupByLeagueName function like this:
function groupByLeagueName(fixtures) {
return fixtures.reduce((result, item) => {
result[item.league_name] = result[item.league_name] || [];
result[item.league_name].push(item);
return result;
}, {});
}
Then in your view you may loop it something like this:
<% for (let leagueName in fixtures) { %>
<p><%= leagueName %></p>
<% fixtures[leagueName].forEach((match, key) => { %>
<p><%= match.home_team %> vs <%= match.away_team %> </p>
<% }) %>
<% } %>

pages.forEach() is not a function

I am trying to display a list of items from a mongodb database in a Node.js application. I am using ejs as a templating engine. I am encountering the following error on the page:
Code for router:
const express = require('express');
const router = express.Router();
// Get page model
var Page = require('../models/page');
// GET page index
router.get('/', function(req, res) {
Page.findOne({}).sort({sorting: 1}).exec(function(err, pages) {
res.render('admin/pages', {
pages: pages
});
});
});
EJS code:
<%- include('../_layouts/adminheader') %>
<h2 class="page-title">Pages</h2>
Add a new page
<br><br>
<table class="table table-striped">
<thead>
<tr>
<th>Title</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<% pages.forEach(function(page) { %>
<tr>
<td><%= page.title %></td>
<td>Edit</td>
<td>Delete</td>
</tr>
<% }); %>
</tbody>
</table>
<%- include('../_layouts/adminfooter') %>
You should replace .findOne() by .find(), .findOne() only return one page object, whereas .find() return an array of objects:
Page.find({}).sort({sorting: 1}).exec(function(err, pages) {
res.render('admin/pages', {
pages: pages
});
});

ReactJS - Creating children components by looping through object

I have parent and child component. I want the parent to render multiple child components with properties specified in an object. I cannot seem to make the loop in the render function work.
var Inputs = React.createClass({
propTypes: {
type: React.PropTypes.string,
xmltag: React.PropTypes.string,
class: React.PropTypes.string
},
getDefaultProps: function () {
return {
type: ' text'
};
},
render: function() {
return (
<div className={'form-element col-xs-6 col-sm-6 ' + this.props.class}>
<label className="col-xs-12">{this.props.text}</label>
<input className="col-xs-12" type={this.props.type} xmltag={this.props.xmltag}></input>
</div>
);
},
});
//OBJECT that needs to be rendered
var formTags = {
id: ["ID", "List ID", "text"],
title: ["TITLE", "List Title", "text"],
said: ["SAID", "SAID", "number"]
};
var InputList = React.createClass({
//PROBLEM STARTS HERE
render: function() {
for (var key in formTags) {
return (
//Not using everything from formTags
<Inputs type="number" text={key}>
);
};
},
//PROBLEM ENDS HERE
});
ReactDOM.render(<InputList />, document.getElementById('mainForm'));
React component must have only one root element, now you are trying render several elements, add one root element, like in example (you can use any elements <div> <p> etc.)
var InputList = React.createClass({
render: function() {
var inputs = Object.keys(this.props.tags).map(function (key) {
return <Inputs key={ key } type="number" text={ key } />;
});
return <div>
{ inputs }
</div>;
}
});
Example

Resources