Michael
Michael

Reputation: 434

Providing different content in res.render dependent on results of array iteration

I initially created a show route for a basic function to get a specific map from a mongodb database (using mongoose) and then rendering the map to the client-side with an .ejs template.

I then wanted to create functionality to favourite a map and add to a user’s favourites (with a user having its own model). As part of this, in the below show route I wanted to ensure that if a user already had a map in their favourites, different content would be rendered on the client-side to reflect that a map had already been favourite rather than continuing to display the option to favourite a particular route.

The method I have been trying to use is shown in the below code. This determines whether an authed user who has favourites is present (using passport-local and its req.user functionality) and then is designed to iterate over the favourites and render different variables if a user already has a map in their favourites.

I am coming up with problems mainly because the if/else routes will be called for all items in the array resulting in a conflict in terms of multiple res.render calls, which is obviously not my intention (it works ok where there is just one item in the array for example). However, I have attempted to amend the code to provide no else route but this still leaves the problem of how to deal with fall-through for rendering separate content where there is a authed user but whose favourites are not present.

I have also attempted to iterate over the favourites in the ejs template itself with the use of a partial through ejs-locals but this again doesn’t seem to work (I suspect for similar reasons as above).

So what I would like to know is whether the array iteration method is appropriate or viable and also a broader question of whether there is a better method for displaying different content on the same route dependent on certain server-side variables.

Client side code

<div class="row">

<% if (favourite == "No") { %>
    <div class="twelvecol" id="result"><div class="textbox" id="favourite">Favourite this route</div></div>

<% } else { %>
    <div class="twelvecol" id="result"><div class="textbox">This route is in your favourites</div></div>

Server side code

// Locates map on basis of ID in url before returning map, stringifying and sending to server

exports.show = function(req, res) {
var mapid = req.query.id;
console.log(mapid);
Map.findOne({_id: req.query.id}, function(err, map) {

         var jmap = JSON.stringify(map);
              if (req.user && req.user.favourites.length) {
                  favarray = req.user.favourites;
                  console.log(favarray);
                  for (var i = 0; i < favarray.length; i++) {
                        var favs = favarray[i];
                        if (favs == mapid) {
                           console.log('Favourite');
                           res.render('show', {obj: jmap, user: req.user, favourite: "Yes"})
                        }
                       else (favs !== mapid) {
                            console.log("Authed user but non-favourite")
                            res.render('show', {obj: jmap, user: req.user, favourite: "No"})
                         }
                      }
                   }
            else {
                    console.log("Either non-authed user or no existing favourites")
                    res.render('show', {obj: jmap, user: req.user, favourite: "No"});
                  }
    })
 };

Upvotes: 0

Views: 1602

Answers (1)

matthias
matthias

Reputation: 2264

In a classical server side MVC sense it is absolutely okay to let the action or even view processing template engine adjust the dynamic portions of your response.

As long as your user object is not exposed to the view (as an ejs local), you should get what you intended that way you started - with some important modifications: 1. Don't render within the loop. (Why?! This must actually result in multiple rendering calls!) 2. Work with variables visible to the action block. 3. Skip the conditional following your else statement! (That works?! I'm curious about how this is evaluated by the parser. Normally you would do that with an else if (condition) or use a switch - but you don't need that in your a/b case!).

A proposal for a step to a cleaner code (only the req.user case):

var fav = false;

for (var i = 0; i < favarray.length; i++) {
  if (favarray[ i ] == mapid) {
    fav = true;
    break;
  }
}

res.render('show', {obj: jmap, user: req.user, favourite: fav})

As an additional advice: Use booleans instead of strings for boolean variables like favourite and handle them as shown below in your ejs template:

<% if (favourite) { %>
  ...
<% } else { %>
  ...

Also you should probably adjust your first if-condition checking if user exists and if the user has favorite items: If you want to handle these two conditions separately, you should not combine them in one condition statement.

Upvotes: 1

Related Questions