Pass data to the same page in express - node.js

i want to pass data from server to the same page if there is an error in the POSTED data.
i have two routes , one route to display the contents and the other route for adding new content. i am using pug as view.
form for the new content is :
extends layout
block content
form(action="/create", method="POST")
h2= title
p
| Text :
input(type="text", name="text")
input(type="submit")
whenever i click the submit button the value in the input is posted
here's the node route.post() code :
router.post('/create' ,function(req,res,next){
if(req.body.text === ''){
res.send("empty")
}else{
contents.push(text: req.body.text )
res.redirect('/')
}
} )
currently if i submit the form without any input value , it will send "empty" msg in a blank page.
What I want is that if the input value is empty, rather than sending "empty" in a blank page i want to send "empty" msg to the same Form page and show anywhere.
like this :
thank you : ) ......

We must use a variable to indicate there is an error. For example:
View
extends layout
block content
form(action="/create", method="POST")
h2= title
p
| Text :
input(type="text", name="text")
input(type="submit")
h2= error
Controller
router.post('/create' ,function(req,res,next){
if(req.body.text === ''){
res.render("your_view_name_here", { error: "empty" })
}else{
contents.push(text: req.body.text )
res.redirect('/')
}
})

Related

Validation error messages are not displayed in angular json schema.

I am using angular-schema-form to display my json data in UI, which works fine as expected.
https://github.com/json-schema-form/angular-schema-form
I wanted a material design for my page, so I used angular-schema-form-material decorator.
https://github.com/json-schema-form/angular-schema-form-material
Example code:
app.js:
require("angular-schema-form")
require("angular-schema-form-material")
require('angular-messages')
require('angular-material')
require('angular-ui-ace')
require('tv4')
require('angular-material/angular-material.css')
var app = angular.module('myApp', [
"schemaForm",'ngMessages', 'ngMaterial', 'ui.ace' ])
controller.js
var signalSchema = { /* Actual schema definition */};
var signalForm = ['*'];
var signalData = {/* Actual json data from DB */ };
index.html
<form name="signalsForm " layout="column" class="canOverviewSignals " sf-schema="signalSchema"
sf-form="signalForm " sf-model="signalData" sf-options="{validateOnRender: true} ">
</form>
The form is rendered properly and validation messages are displayed without material decorator. But on including the decorator the validation messages are not displaying. For example when a 'required' value is not entered, the error message 'field is required' is not displayed when the decorator in included. The below error message is displayed in browser console.
View Console error message here

Post does not include all values

I am playing with node.js and jade and currently have this simple template:
extends layout
block content
h1 #{title}
br
form(action="/updateingredient", method="post")
table.table.table-striped.table-bordered
tr
td Name
td Category
td Available
if (typeof ingredients === "undefined")
tr
td
else
each ingredient in ingredients
tr
td #{ingredient.name}
td #{ingredient.category}
td
input(type="checkbox", name="#{ingredient.id}",
value="#{ingredient.available}", checked=ingredient.available)
button.btn(type="submit") Update Ingredients
When submitting this I get hit in upgradeIngredients as expected:
updateIngredient: function (req, res) {
console.log(req.body);
}
My problem lies in. That the Post only includes the checkboxes that are checked, also the value of checked boxes always seem to be false. I presume that is because that was the value before the form Post.
What I preferably would like is to get all checkbox values in the form, checked or not. Is this possible?
The current output from the updateIngredient method gives me the following when a checkbox is checked (currently just testing with one item):
{ 'b56a5f79-b074-4815-e7e0-4b746b2f65d8': 'false' }
and when unchecked:
{}
Edit
Looking at the constructed HTML I see this for an item:
<tr>
<td>Ost</td>
<td>Mælkeprodukt</td>
<td>
<input
type="checkbox"
name="b56a5f79-b074-4815-e7e0-4b746b2f65d8"
value="false"
checked="false">
</td>
</tr>
Verify that the checkbox HTML is correctly constructed
look in console for errors and warnings
ensure that the boxes all have either "true" or "false" for the checked value.
This example contains working syntax:
Node Express Jade - Checkbox boolean value
After searching some more here on SO, I found this answer: Post the checkboxes that are unchecked
It seems like checkboxes, which are not checked are not part of a form when posting HTML. This is exactly what I am seeing.
I did change my checked code to the following before going down another path.
checked=ingredient.available?"checked":undefined
This did not change anything, and did not give me any data in my form post when unchecked.
So I used the JavaScript approach, adding a submit event handler to my form. I added a new checkbox.js file in my javascripts folder, this code is taken from this answer:
// Add an event listener on #form's submit action...
$("#updateform").submit(
function() {
// For each unchecked checkbox on the form...
$(this).find($("input:checkbox:not(:checked)")).each(
// Create a hidden field with the same name as the checkbox and a value of 0
// You could just as easily use "off", "false", or whatever you want to get
// when the checkbox is empty.
function() {
console.log("hello");
var input = $('<input />');
input.attr('type', 'hidden');
input.attr('name', $(this).attr("name")); // Same name as the checkbox
// append it to the form the checkbox is in just as it's being submitted
var form = $(this)[0].form;
$(form).append(input);
} // end function inside each()
); // end each() argument list
return true; // Don't abort the form submit
} // end function inside submit()
); // end submit() argument list
Then I added the script to the end of my layout.jade file:
script(src='/javascripts/checkbox.js')
And I modified my form to include an ID:
form#updateform(action="/updateingredient", method="post")
And removed the value from the checkbox:
input(type="checkbox", name="#{ingredient.id}",
checked=ingredient.available?"checked":undefined)
Now I get the following when value is unchecked:
{ 'b2a4b035-8371-e620-4626-5eb8959a36b0': '' }
And when checked:
{ 'b2a4b035-8371-e620-4626-5eb8959a36b0': 'on' }
Now in my method I can find out whether it was checked or not with:
var available = req.body[ingredient] === "on" ? true : false;
Where ingredient is the key.

How to conditionally show different UI in Jade?

I have the following template:
extends layout
block content
#wrapper
#logo
a(href='/')
p #{title}
#msg
| hi #{user}
#display
#register
----A registration form here----
#login
----A login form here-----
include footer
If the user opens this page via POST and I use a token to decide if he is logged in like so:
exports.home = function(req, res) {
// if user is not logged in, show both login and register forms
if (typeof req.session.username == 'undefined') {
res.render('home', { title: 'Online Coding Judge'});
}
// if user is logged in already, just say hi to him
else {
// what here???
}
};
How do I show different things on the page depending on whether he logged in or not?
EDIT: A more realistic example would be to show an error message if there was a failed login in the same UI I would need to conditionally show an error message.
Something like this should work:
EDIT: revised:
block content
#wrapper
#logo
a(href='/')
p #{title}
if {user}
#msg
| hi #{user}
#display
#register
----A registration form here----
#login
----A login form here-----
else
--- some other logic ---
include footer

How to know if block content is empty in Jade

How can we check if block is exist in Jade, I'm trying to make a template in Jade where in i have following block in layout.jade and in login.jade i have extended layout.jade. Now when in account.jade i will have both left and main content blocks
extend layout.jade
div(class='col-md-4')
block leftcontainer
div(class='col-md-8')
block content
Now in login.jade i want to hide
div(class='col-md-4')
block leftcontainer
and make the main content full page, if leftcontainer is not there. It should look like this
div(class='col-md-12')
block content
if user is on some page i want to hide left column block. Say if user is in login page then
If I got it right, you wan't to hide a block if a user (e.g. a user who is logged in to your app) is at a certain page. If this is right do something like this:
Example with Express & Passport:
// server
app.get('/login', function(req, res){
if(req.isAuthenticated()) {
res.render('login', { 'user' : req.user } );
} else {
res.render('login', { 'user' : null } );
}
});
// layout
extend layout.jade
if user !== null
div(class='col-md-12')
block content
else
div(class='col-md-4')
block leftcontainer
div(class='col-md-8')
block content
In general you can work with other conditional statements in Jade, without Passport, this was just an example. You may want to take a look at the reference, especially under conditional or case.

(Post/Redirect/Get pattern) Laravel layout variables don't work after redirect

I'm using the Post/Redirect/Get (PRG) pattern in my Laravel controllers to prevent duplicate form submission.
It works well when I don't use layouts or when my layouts don't use any variable. The problem is my layout uses a variable named $title. When I load the view and the layout without redirect it works well, the title set in the controller is passed to the layout, but after processing a form and redirecting to the same route which uses the same layout and the same controller method I get a "Undefined variable: title" error coming from my layout file.
Here is my code:
File: app/routes.php
Route::get('contact', array('as' => 'show.contact.form', 'uses' => 'HomeController#showContactForm'));
Route::post('contact', array('as' => 'send.contact.email', 'uses' => 'HomeController#sendContactEmail'));
File: app/controllers/HomeController.php
class HomeController extends BaseController {
protected $layout = 'layouts.master';
public function showContactForm()
{
$this->layout->title = 'Contact form';
$this->layout->content = View::make('contact-form');
}
public function sendContactEmail()
{
$rules = ['email' => 'required|email', 'message' => 'required'];
$input = Input::only(array_keys($rules));
$validator = Validator::make($input, $rules);
if($validator->fails())
return Redirect::back()->withInput($input)->withErrors($validator);
// Code to send email omitted as is not relevant
Redirect::back()->withSuccess('Message sent!');
}
}
File: app/views/layouts/master.blade.php
<!DOCTYPE html>
<html>
<head>
<title>{{{ $title }}}</title>
</head>
<body>
#yield('body')
</body>
</html>
File: app/views/contact-form.blade.php
#section('body')
#if (Session::has('success'))
<div class="success">{{ Session::get('success') }}</div>
#endif
{{
Form::open(['route' => 'send.contact.email']),
Form::email('email', null, ['placeholder' => 'E-mail']),
Form::textarea('message', null, ['placeholder' => 'Message']),
Form::submit(_('Send')),
Form::close()
}}
#stop
I don't understand why after redirecting the next line of code is ignored
$this->layout->title = 'Contact form';
I've tried with Redirect::action('HomeController#sendContactEmail'); or Redirect::route('show.contact.form'); but the result is the same.
The controller in charge of rendering that view is exactly the same before the redirect than after the redirect, and it has no business logic at all, so why it only works on the first case but not in the second?
This
Redirect::back()->withSuccess('Message sent!');
should be
return Redirect::back()->withSuccess('Message sent!');
When layout attribute is set in a controller and method is not returning any response, controller try to render the layout. In your sendContactEmail() method both conditions fulfilled and controller tried to render layout before $title is set.
see callAction() in Illuminate\Routing\Controllers\controller.
http://laravel.com/api/source-class-Illuminate.Routing.Controllers.Controller.html#93-127
Have you tried using
return View::make('contact-form', array('title' => 'Contact Form'));
Instead of interacting with the layout directly?
Redirect::back() creates a 302 using the referer value of the current HTTP request. I would start by comparing the initial form request to the redirect request to see if that yields any clues. You could also try...
Redirect::route('HomeController#showContactForm')->withInput()...
I know it's less dynamic but it will generate the URL rather then rely on the referer value in the HTTP header.

Resources