Passing Client-side JavaScript Param to Server-side JavaScript method - javascript

Guys I've search for a solution for this problem with no luck, wish if someone could help.
I'm building nodejs express app, in one of .ejs I'm trying to compare mongoDB Id of the selected item with the id passed in the query string in order to change the selected item accordingly.
Below is the code:
<table class="table table-striped">
<tr>
<th>Available Models</th>
</tr>
<script>
<% var index = 0; %>
</script>
<% if(modelId) { %>
<script>
for(i =0; i <= document.getElementById("mnumake").options.length;i++) {
var optionValue = document.getElementById("mnumake").options[i].value;
if (<% modelId.equals(%> optionValue <% ) %> ) {
index = i;
document.getElementById("mnumake").options[i].selected = true;
break
}
}
</script>
<% } %>
<% makes[index].models.forEach(function(model){ %>
<tr><td><%= model.name %></td></tr>
<% }) %>
</table>

Related

How can I refactor my 'view' code to display items per year?

I would like to refactor a piece of code in order to display / regroup my items per year without repeating the code for each of the years. As of now, I've tried looping through an array of years, but it didn't seem to work.
Here is the piece of code I'm currently repeating in a 'view' file (ejs template) for 8 different years :
<ul><h3>YEAR 2017:</h3>
<% items.forEach(function(el){ %>
<% if(el.date.substring(7, 11) == "2017"){ %>
<li><%= el.date %>:
<% if(el.url){ %>
<%= el.title %>,
<% }else{ %>
<%= el.title %>,
<% } %>
<% if(el.by){ %>
<%= el.type %>, <%= el.by %>
<% }else{ %>
<%= el.type %>
<% } %>
# <%= el.location %></li>
<% } %>
<% }); %>
</ul>
Seems like you are already on the right track by using an ejs template and using an array. Maybe you should restructure the way you are passing the items so that they are in an array of objects like so
items = [{"year": 2016, "items": [item1,item2...]},{"year":2017, "items": [item1,item2..]}, ... ]
Then you could loop through them in this way:
<% items.forEach(function(year){ %>
<ul><h3>YEAR <%= year.year %>:</h3>
<% year.items.forEach(function(el){ %>
...
<% } %>
<% } %>
maybe like this, please convert to eje syntax:
let arr = []
let arrEl = items.map(function(el, index){
return el.date.substring(7, 11);
})
arr.push(arrEl)
for (let i=0; i<arr.length; i++){
items.map(function(element, index){
if(el.date.substring(7, 11) == arr[i]){
//show your el
}
})
}

JavaScript dynamic object keys ejs

I really cannot find a way to describe this. Essentially I have a database that can have any number of tables with different column lengths and names. I have a table which defines each table and it's columns. I have a query to search for values within these tables, and I pass the results of the search and the columns to ejs using express. What I need is to echo the results. I do have:
<div class="row">
<table>
<thead>
<tr>
<% columns.forEach(function(column) { %>
<th><%= column %></th>
<% }); %>
</tr>
</thead>
...
This outputs the name of the columns in the table header correctly. I cannot for the life of me figure out how to print the actual results however. I have tried many different ways but all I keep getting is undefined or [Object object]. I have this currently:
<tbody>
<% for(var r = 0; r < results.length; r++) { %>
<tr>
... need to access column here ...
</tr>
<% } %>
</tbody>
I first tried the following (inside above)
<% for(var key in Object.keys(results[r])) { %>
<%= results[r].key %>
<% } %>
followed by so many different attempts along the lines of this. I suppose the issue is not knowing the possible key names. I don't even know what to search for either to be entirely honest. My mind is drawing a blank.
Any help is much appreciated.
Object.keys returns an array of all the keys in an object. You can use forEach to iterate over those keys, to access the value of the object via object[key]
Also, you can use forEach on your results instead of for to keep things clean.
<% results.forEach(function (result) { %>
<tr>
<% Object.keys(result).forEach(function (key) { %>
<td><%= result[key] %> </td>
<% }) %>
</tr>
<% }) %>
Modern browsers have arrows now, so this can be simplified a little:
<% results.forEach(result => { %>
<tr>
<% Object.keys(result).forEach(key => { %>
<td><%= result[key] %> </td>
<% }) %>
</tr>
<% }) %>

How to break a loop with the EJS template language?

I am developping a simple web application with sails.js.
In my frontend code, i'm looping over an array of objects sent by the controller, and i am searching for a specific object. I'd like to break the loop once the object has been found. Is there a clean way to do that using the ejs template language ?
I coulnd't find anything about it on the EJS official website, nor on sails website.
I naively tried this until now :
<% objects.forEach(function(object) { %>
<% if(object.someId == someValue) {%>
<%= object.name %>
<% break %> <!-- This raise an illegal statement exception -->
<% } %>
<% } %>
The following code works as expected, but i'm looking for a cleaner solution if any
<% var found = false %>
<% objects.forEach(function(object) { %>
<% if(object.someId == someValue && !found) {%>
<%= object.name %>
<% found = true %>
<% } %>
<% } %>
It's not an EJS-related question.
break statement terminates the current loop. While you are not inside a loop. You are inside callback function, that's called by forEach method once per array element. There's no ability to interrupt forEach (see How to short circuit Array.forEach like calling break?). But, if you need it, you may use for loop for a clean solution:
<% for (var l = objects.length, i = 0; i < l; i++) { %>
<% object = objects[i]%>
<% if(object.someId == someValue) {%>
<%= object.name %>
<% break %> <!-- This will work as expected -->
<% } %>
<% } %>

Javascript cannot get value for operation

I have the following issue. Since there're many, many business rules I've decided to enter those functions as js to update automatically.
In my view i have:
this is inside a table
(<%= javascript_include_tag 'people'%>)
<th>Name</th>
<th>Money</th>
<th>Money Comment</th>
</tr>
<% #counter = 0 %>
<% #people.each do |p| %>
<% #counter += 1 %>
<tr>
<%= form_for(:p) do |f| %>
<th><%= f.label(p.name) %></th>
<th><label for="<%= "money_" + #counter.to_s %>"> <%= f.select(:money, 1..10, :selected => p.money)%></label></th>
<th><label for="<%= "comment_" + #counter.to_s %>"> <%= f.label(p.money_comment, :disabled => 'disabled')%></label></th>
<% end %>
<% end %>
and in the javascript the function looks like this:
function change_people() {
money1 = $('money_1').getValue();
if (money1 == 10) {
$('comment_2').setValue("I know what you're doing you mofo");
}
else {
$('comment_2').setValue("");
}
}
document.observe('dom:loaded', function() {
change_people();
$('money_1').observe('change', change_people);
});
but for some reason it keeps telling me it doesn't know what I mean by "money_1". I check the html source and is compiling the view, am I referencing the element wrongly in js?
Thanks for the help!
It looks as if you need a selector:
<th id="<%= "money_" + #counter.to_s %>">
<label for="<%= "money_" + #counter.to_s %>">
<%= f.select(:money, 1..10, :selected => p.money)%>
</label>
</th>
Now you've given Prototype the ability to search and find the correct element (the select with the value you're looking for), which you pass to the $() function to call getValue():
function change_people() {
// Note the "#" on #money_1, which is an ID selector
// the space " " between is a descendant element selector
money1 = $($$('#money_1 select')).getValue();
if (money1 == 10) {
// do stuff
} else {
// do other stuff
}
}
If you're looking to iterate over all of the money select values in the table, you would instead want to use a class; you are only allowed to have one element per ID, but a class by rule is grouped by attribute. The difference would be:
<th class="money_select">
<label for="<%= "money_" + #counter.to_s %>">
<%= f.select(:money, 1..10, :selected => p.money)%>
</label>
</th>
And then in your javascript:
function change_people() {
// Note the "." on .money_1, which is a class selector
// the space " " between is a descendant element selector
$$('.money_select select').each(function(element){
if ($(element).getValue() == 10) {
// do stuff
} else {
// do other stuff
}
});
}

Is it right to generate the javascript using C# in ASP.NET MVC view page?

[Sorry for long question but it is necessary to explain the problem]
I am working on a learning website and it is supposed to show a list of messages to user if there are any. Something like this:
When user presses close button, that message must be marked "read" and should not be shown next time. Following code is used to generate those messages:
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" value="Close<%= Html.AttributeEncode (m.ID) %>" id="c<%= Html.AttributeEncode (m.ID) %>"/>
<% } %>
</div>
<% } %>
After that, following the guidelines, I added the support of http post method in controller which marks the message as read and then refreshes the view (to handle disabled JavaScript):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CloseMessage (int id) {
using (var dl = new DL ()) {
dl.MarkAsRead (id);
}
if (Request.IsAjaxRequest ()) {
return new EmptyResult ();
}
else {
return RedirectToAction ("Index");
}
}
Then I wanted to add JavaScript support such that only the message goes away (using jQuery). But the problem is that I am generating the buttons and messages programmatically.
So ended up with a weird looking javascript code in viewpage:
<script type="text/javascript">
$().ready(function() {
<% foreach (var m in Model.UserMessages) { %>
$("#c<%=Html.AttributeEncode (m.ID) %>").click(function(event) {
$.post("Home/CloseMessage/<%=Html.AttributeEncode (m.ID) %>");
$("#m<%=Html.AttributeEncode (m.ID) %>").slideUp("slow");
event.preventDefault();
});
<% } %>
});
</script>
This is basically creating the javascript code in a C# loop which actually works but too much for me to digest. Is there any better way of doing this?
You could just create one javascript function that takes the element IDs as parameters :
function myFunction(ID) {
$.post("Home/CloseMessage/" + ID);
$("#m" + ID).slideUp("slow");
}
And :
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" value="Close<%= Html.AttributeEncode (m.ID) %>"
id="c<%= Html.AttributeEncode (m.ID) %>"
onclick="myFunction('<%=Html.AttributeEncode(m.ID)%>')"/>
<% } %>
</div>
<% } %>
YOu could uses a CSS selector in your JS to get all buttons with a particular class assigned to them. Then you can wire up you click event to them. So your HTML would be something like this:
<% foreach (var m in Model.UserMessages) { %>
<div class="um" id="m<%=Html.AttributeEncode(m.ID) %>">
<p class="mh"><%= Html.Encode (String.Format ("From {0} ({1})", m.From, m.Sent)) %></p>
<p><%= Html.Encode (m.Text) %></p>
<% using (Html.BeginForm ("CloseMessage", "Home", new { id = m.ID })) { %>
<input type="submit" class="MyCloseButton" value="Close<%= Html.AttributeEncode (m.ID) %>" id="c<%= Html.AttributeEncode (m.ID) %>"/>
<% } %>
</div>
<% } %>
I've only added the class="MyCloseButton" to your input
Then in your JS (I use mootools but JQuery has CSS selectors too but you will need to port it sorry) you can do something like this:
window.addEvent( "domready", function() {
$$("input.MyCloseButton").each( function( button ) {
// Add your code here, you can reference button.id etc for each of your buttons
}
});
This way you only have to write out one little function in plan JS and not worry about doing it server-side, all you need to do it decorate your buttons with a css class so the JS can find them.
I understand its not pretty, but its not that bad either. I think there are easier ways to do this, however.
You can use jquery's positional selectors from the button's click event handler. Then just assign the same handler to every button.
<script type="text/javascript">
$(document).ready(function() {
$("input[type=submit]").click(function(){
$(this).parent().slideup("slow");
$.post("Home/CloseMessage/" + $(this).parent().attr("id"));
event.preventDefault();
});
});
});
</script>

Categories

Resources