Render partial view with jade on select change - node.js

I need to do the following,
I have a <select> (a list of team names), when the user selects a team, I get relevant information re: the team and display it.
How do I do this in jade?
I'm trying the following, (but I'm wrong obviously, I don't see a lot of documentation out there).
Briefly, I'm doing a include test.jade on my main page, and a res.render('test', {team: team_obj});
jade:
h1 #{team}.name
h2 #{team}.homeGround
h3 #{team}.manager
h4 #{team}.aka
nodejs:
collection.findOne(query, function(err, team_obj){
res.render('test', {team: team_obj});
});
I'm getting the information correctly in team_obj.
Get the following error when I run the app,
team is not defined
Now this is happening because test.jade is getting rendered before I feed it the team_obj.
Questions:
1) Am I doing this right? is include the correct way of partially rendering jade views? if yes, how do I make sure it renders only when the user has selected an option?
2) Is there a partial views concept in jade I'm unaware of?

1) you should use #{team.name}
2) you can't change the team object once the selector is changed. the template was rendered once with the database result. - such functionality should be handled by client side JavaScript and AJAX calls. partials in templates are just a way to share common pieces of templates, and its done in Jade via include.
I don't know what you're rendering and including and when.. but id you use a template variable like #{team.name} you have to make sure that the template was rendered with the team object.

Related

Set parameter for URL in html and use parameter in Node.js Express for routing

I very much new to Node JS and Express Framework & mongodb. I am working on a website which has multiple categories and when we click on category it goes to a view, where based on the category clicked, data gets loaded in the view.
please check the link for website here.
I am looking help for navbar links eg. Montessori Premium->Toddler Material
As these are static links I can not figure how to pass any parameter or url format for this.
I have done the routing for individual products as they have ids coming from database so I am using that id in url.
Thanks in advance.
It seems to me like you're just missing a bit of glue in between the front-end and the back-end database calls. Here's a rough idea of the sequence you might be after and an explanation of what I think you're missing.
If I'm wrong, please add a comment and update your question to include the new details and I'll see about editing my answer.
In this example I'm creating a website which has a list of "items" in a shop and we're looking to display them all on a single page. Each item should then have an a href clicking through to that specific item where there might be more detail such as a "full description" of the item and maybe some images or something. We're going to look at the flow to build that first page with the list of items.
The user makes a HTTP GET call to the root of your website such as "http://www.mystore.com/".
This request comes through in Express to your controller which takes the req, res, next parameters.
Your controller makes a call to the database to get a list of all items including their names and ID's.
You then use something called templating to inject in the list of items.
In this template you iterate through the list doing something like this.
.
<ul>
{{#each items}}
<li><a href="/items/{{id}}>{{name}}</a></li>
{{/each}}
</ul>
In this template (which happens to be Handlebars), we're going through the list of items and using the id and name of each to inject them into the HTML to get something a bit like this back.
<ul>
<li><a href="/items/1>Shoes</a></li>
<li><a href="/items/2>Red spotted dress</a></li>
<li><a href="/items/3>Jeans</a></li>
</ul>
This is then served up to the user once the template has been processed.
In essence I think you're after some sort of templating engine, I'd highly recommend having a look at Handlebars with something like the express-hbs.
Thank you #Elliot for your time to answer this. Yes I am using handlebars for templating. The solution I found is, because I am using static links, I am passing query string in anchor tag link.
eg. http://localhost:8000/product?category=Toddler_Material
and then using req.query for capturing the values (Toddler_Material) in router
var category = req.query.category;

Can I render all zones to an HTML string in a controller method

I'm trying to render the HTML for a content item to a string from within a controller action. Technically I just want to get the "body" part of it without any header/footer stuff. I want to do this so I can get a content item rendering the way I want once, and then display it as a normal orchard page OR by requesting the HTML for the content item via ajax to display it in a div in a JavaScript app. I don't want to have to manually render everything in the JavaScript as that would be duplicating the layout logic I already did. I want to re-use the bulk of the server side rendering so any changes are reflected in my normal orchard page and my JavaScript page. I've been digging into the code and searching everywhere and have gotten close but not all the way there.
I found these:
How to render shape to string?
Using FindView in Orchard
In my controller I have:
var shape = _contentManager.BuildDisplay(contentItem);
Using either of the two methods above, I can render that shape to an HTML string in my controller. All was golden. I was getting the body of that page and using it in JS. Then, I changed a placement file:
<Place Parts_Common_Body="Content:1" />
was changed to:
<Place Parts_Common_Body="/AsideFirst:1" />
The body moved where I wanted it (AsideFirst) in my normal Orchard page but disappeared from the HTML retrieved using the two methods above.
If I look at shape.Content.Items after the BuildDisplay call, I can see the item for the body is no longer there... why is it not rendering all the zones? Or, I guess a more specific question is why is the BuildDisplay method not building the complete shape? Is there a way I can make this work?
I tried a million different things and eventually got this working. Not sure I totally get it yet, but I think the problem had to do with the fact that I was using shape.Content and I'd moved stuff out of the Content zone. And maybe when I was looking at what the BuildDisplay method was returning I was just not looking at some newly created zone that actually did had the stuff I thought was missing. Clearly I need to learn more about zones and shapes... Anyway, I have a new zone called "MainInfo" now that I created in a placement file. I get a MainInfo property on the main shape returned form BuildDisplay and pass shape.MainInfo to the view rendering code and all seems to be working well now.

Reusing Yesod widgets in AJAX results

I'm writing a very simple Yesod message list that uses AJAX to add new list items without reloading the page (both in the case of other users modifying the database, or the client themselves adding an item). This means I have to encode the HTML structure of the message items in both the Halmet template (when the page loads initially) and the Julius template (for when the dynamic addition happens). They look something like this:
In homepage.hamlet:
$if not $ null messages
<ul id=#{listId}>
$forall Entity mid message <- messages
<li id=#{toPathPiece mid}>
<p>#{showMarkdown $ messageText message}
<abbr .timeago title=#{showUTCTime $ messagePosted message}>
And in homepage.julius:
function(message) {
$('##{rawJS listId}').prepend(
$('<li>')
.attr('id', message.id)
.append('<p>' + message.text + '</p>')
.append($('<abbr class=timeago />')
.attr('title', message.posted).timeago())
.slideDown('slow')
);
}
I'd love to be able to unify these two representations somehow. Am I out of luck, or could I somehow abuse widgets into both generating an HTML response, and filling in code in a JavaScript file?
Note: Of course, I understand that the templates would have to work very differently, since the AJAX call is getting its values from a JS object, not from the server. It's a long shot, but I thought I'd see if anyone's thought about this before.
I think it's something of a AJAX best-practice to pick one place to do your template rendering, either on the server or client. Yesod is (currently) oriented toward doing the rendering on the server.
This can still work with AJAX replacement of contents, though. Instead of getting a JSON response from the POST, you should get a text/html response that contains the result of rendering the template on the server with the values that would have been returned via JSON and then replacing the innerHTML of the DOM node that's being updated.
If you want to support both JSON and HTML responses (to support 3rd party applications via API or something) you would have to make the format of the response be a function of the request; either appending ".json" or ".html" to the URL or including a HTTP header that lists the specific document type required by the client.
It would be nice if Yesod provided a 'jwhamlet' template or something that would render the HTML via javascript in order to support client rendering, but I'm not aware of one. That's not to say there isn't one I'm not aware of, though, so keep an eye open for other answers.
If you wanted to make such a thing, you might try tweaking the hamlet quasi-quote code so that instead of expanding the quasi-quotes to an html-generating function, it expanded them to a JSON-generating function and a pre-rendered chunk of text that's a template in mustache-style such that the JSON returned by the function would provide the correct context for the template to be rendered the way you want.

rendering some dynamic blocks on page - express.js + jade

Looking for a solution for a few days. Need help.
Source:
node.js + express.js + jade template engine
Problem:
Can't understand how I can render 1+ dynamic blocks on one page.
For example:
We have a page: News main page
Blocks on page: Latest news (list 20 itens), hot news (list 4 items), most viewed news (4 items), block with news categories (it can display current category on the page with page with card of one selected novelty, so it is dynamic block too), and block with some user auth data.
"block" i mean a widget as we can see on site, not a block of code.
What can I do in express? I can route special url to special function in routes.
So as I see, if a want to render all this blocks on the one page I have to call all functions rendering each block in only one function of route.
I mean it seems that I have to do something like this (sure in libs but doesn't matter here)
app.get('/news', function(req, res){
call_last_news(funcion(){
call_hot_news(function(){
call_get_user_info(function(){
...
...
...
template.render.here();
final_here();
});
});
});
});
This looks real but so unuseful and unsupportable code that .. That's bad.
I can see solution in calls from template engine to render some blocks on the page. But not just include because all blocks can use db or cookies, session data etc. all blocks are dynamic. But I have no idea how to create such engine using express.js + jade
Well I'm not certain I understood all of the problem but based on the pseudo code, it looks like the main concern here is that you have a deeply nested set of potentially independent and reusable functions. There are two approaches to this problem that come to mind:
Use a control flow library
Use something like async series, parallel, etc. (which function depends on the nature of your code – are all of the call_ functions independent?) That will clean up your code and make it more maintainable.
Use ajax
Another approach you can take is to quickly render the page without all of the call_ functions and just make several ajax calls from the client to fill in the data. You could have routes which look like '/news/last', and '/news/hot', etc. This is nice because you can separate out all of the logic for each of these units into reusable URLs so you can mix and match them on any page.

How to provide the current route or view to the layout in ExpressJS?

I want to be able to dynamically reference JavaScript and Stylesheets depending on which page a user is on in Express. I thinking the best way to do so (though I'm open to suggestions) is to pass the current view to the layout page.
For example;
Given the url http://example.com/trees
I would want to have some logic in layout.jade that said something to the effect of:
script(src="/javascripts/{view}.js")
Which would get rendered as:
<script src="/javascripts/trees.js"></script>
Any suggestions or best practices for doing this?
req.route is the matched route, so things like req.route.path etc are available, or of course req.url which may be parsed. With express 2x you can expose these values to views automatically using "dynamic helpers" or res.local()
There are no best practices for doing this, since Express doesn't provide Rails like url helpers, so I think you're approach is fine.
The easy answer is to just put ALL your javascript into a single file and be done with it. Ditto for CSS. See the Ruby on Rails asset pipeline for details. You are probably making your life more complicated than necessary and also less efficient by having different javascripts on different pages.
However, since you asked, the answer for javascripts is easy. Just put the extra <script> tags in the view, not the layout. Problem solved. CSS doesn't work as cleanly because the <link> tags need to be inside the <head>. In this case, I define the styles I need as an array of strings and loop over that in my layout template. So in my route I set up a local variable such as
locals.css = ['/css/one.css', '/css/two.css']
Then just loop over that in your template and generate one <link> tag for each.

Resources