I would like to use the off canvas sidebar in conjunction with my table. Im using node js express app and an ejs view engine to get dynamic values for my table. Im not really sure how I'd go about creating the off canvas side bar. Im guessing I would have to use an anchor tag with my <tbody> rows.
<% if (terms.length > 0) { %>
<% terms.forEach(term => { %>
<tbody>
<tr>
<th scope="row"><%= term.id %></th>
<td><%= term.term %></td>
<td><%= term.definition %></td>
</tr>
</tbody>
<% }) %>
<% } else { %>
<div class="alert alert-danger" role="alert">
There are no terms or definitions to view
</div>
<% } %>
Considering the above code, I want the user to be able to click on the term ,which is. <td><%= term.term %></td> then the sidebar appears with the term, id and definition nicely presented on the off canvas.
Any help would be appreciated
I recently had to work on an old codebase with this and I "solved" it by including the slider as a component on each loop, then I passed in the record I wanted to use in the slider.
In your case, you would do these:
Abstract the slider into it's own .ejs file
Update your table loop to include the slider:
<% terms.forEach(term => { %>
<%- include('./path-to-your-slider-component-ejs', { term } ); %>
Add an identifier to the data-bs-target used by offcanvas to target the slider you want to open up:
<a href="#" data-bs-toggle="offcanvas" data-bs-target="#yourSliderId<%= term.unique_id %>" aria-controls="yourSliderId<%= term.unique_id %>">
View Term
</a>
In your slider file, accept the passed in term and attach the term.id to the ID used in targeting it for opening like:
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="offcanvas offcanvas-end" style="width: 35%;" tabindex="-1" id="yourSliderId<%= term.unique_id %>" aria-labelledby="yourSliderId" aria-modal="true" role="dialog">
...
</div>
</div>
</div>
You can go ahead to render the remaining content as you see fit in this slider.
PS: This was the best workaround I could think of - given the situation -, hen it might not be the best approach so please consider the possible drawbacks this might have and whether using a frameworks like React or Vue might be a better way to go for your project.
Related
Let's say I have one view
users.handlebars
{{#each users}}
<tr>
<td>{{this.id}}</td>
<td>{{this.profile.firstname}}</td>
<td>{{this.profile.lastname}}</td>
<td>{{this.profile.location}}</td>
<td>{{this.email}}</td>
<td>{{this.profile.status}}</td>
<td><i class="fas fa-user-edit"></i>
<a class="user-ban-btn" href="javascript:void(0)">
<i class="fas fa-hand-paper"></i>
</a>
<a class="user-delete-btn" href="javascript:void(0)"> // THIS IS DELETE BUTTTON
<i class="fas fa-trash"></i>
</a>
</td>
</tr>
{{/each}}
And another
main.handlebars
<div class="modal-box" id="user-delete-modal">
<div class="modal-box-message">
<p>Are you sure u want to delete this user?</p>
YES
NO
</div>
</div>
In first view, I click on button delete user but I need to parse data from this view to the second view where I choose YES or NO because yes have a link with ID parameter /users/delete/:id But i don't know to do it.
Note: Main.handlebars is template and users.handlebars is inserted into this template and that modal box is opened just with javascript there is no page refresh.
I will be thankful for any idea how to make it.
Solved by adding onClick="get_user_id(this.id)" to a element.
And then taking it with javascript.
Context
I have a GET route that loads a .ejs file which adds rows of data to a table based on the length of the passed variable accounts. Here accounts is an array of dictionaries with the keys _id, type, nickname, rewards, balance, customer_id.
<% if (accounts.length > 0) { %>
<% accounts.forEach(account => { %>
<tr class="blue-grey lighten-3 account-row">
<th scope="row" class="account-id"><%= account._id %></th>
<td><%= account.type %></td>
<td><%= account.nickname %></td>
<td><%= account.rewards %></td>
<td>$<%= account.balance %></td>
<td><%= account.customer_id %></td>
<td>
<span class="table-remove">
<button type="button" class="btn btn-danger btn-rounded btn-sm my-0 remove" data-toggle="modal" data-target="#removeAccountModal">
Remove
</button>
</span>
</td>
<div class="modal fade" id="removeAccountModal" tabindex="-1" role="dialog" aria-labelledby="removeAccountModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="removeAccountModalLabel">You are about to remove this account</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
CAUTION!!!
<br>
<br>
Removing this account will delete all the data associated with it. You must visit a local branch to retrieve any monies left residing in the account.
</div>
<div class="modal-footer">
<button type="button" class="btn grey darken-1" data-dismiss="modal">Cancel</button>
<form id="remove-form" action="/" method="POST">
<button id="removeAccount" class="btn btn-primary" type="submit">Remove Account</button>
</form>
</div>
</div>
</div>
</div>
</tr>
<% }) %>
Issue
There is a delete button on each row of data that opens a Bootstrap modal confirming that the user wants to indeed delete that row's data. Upon a submit in the modal, this will initiate a DELETE request in the form of a form element.
I want to pass the selected row's associated account._id variable so that I can modify the form's action attribute to /<%= account._id %>/?_METHOD=DELETE.
I am having trouble accessing the modal's parent window DOM elements.
My jQuery code is as follows:
<script>
$(document).ready(function () {
console.log("loaded and ready to go!"); // works as expected
var $remove = $(".remove"); // works as expected
console.log($remove.length); // works as expected
$(".remove").click(() => {
console.log("I'm in the modal!") // works as expected
var $parent = $(this).parent().closest("tr"); // find row
console.log($parent); // w.fn.init [prevObject: w.fn.init(0)]
var $account_id = $parent.find("th"); // find account id
console.log($account_id); // w.fn.init [prevObject: w.fn.init(0)]
console.log($account_id.text()); // returns blank type string
$("#remove-form").prop("action", "/" + $account_id + "?
_method=DELETE"); // change action attribute to account id value
})
});
</script>
Methods tried:
console.log(window.parent.$(this).closest("tr"));
// returns w.fn.init [prevObject: w.fn.init(1)]
you have placed the modal inside the forEach loop. So you dont have only one modal, instead you have one for each row. The problem here is that you assigned the same id removeAccountModal for all of them. Try to assign a unique id for each modal, for example:
<div class="modal fade" id="<%= account._id %>" tabindex="-1" role="dialog" aria-labelledby="removeAccountModalLabel" aria-hidden="true">
and on each delete button replace data-target with
data-target="#<%= account._id %>"
So you have unique modals and now you can place <%= account._id %> directly in action attribute
Thank you #dimitris tseggenes for pointing me in the right direction.
The unique ids for each modal div was imperative here. It turns out the id attribute value must not solely consist of numbers.
I refactored the id and target-data attributes to look like the following, respectively:
id="account<%= account._id %>id"
data-target=#account"<%= account._id %>id"
I have learned the following from the responses in this post:
Don't forget to make modal divs unique if you will have multiple modals, i.e. in a table and to alter the action element respectively using the data-target attribute
id attributes must not solely contain numbers
I am making a website with node.js and I am new ,I want to learn a method if there is.I list cars using ul and when I click on a car name i want to show car's details. How can I do it.
html
<template name="vehicles">
<section id="vehicles" class="container">
<div class="row">
<div class="col-md-12">
<h2 class="title wow fadeInDown" data-wow-offset="200">Vehicle Models - <span class="subtitle">Our rental fleet at a glance</span></h2>
</div>
<!-- Vehicle nav start -->
<div class="col-md-3 vehicle-nav-row wow fadeInUp" data-wow-offset="100">
<div id="vehicle-nav-container">
<ul class="vehicle-nav">
{{#each showcarnames}}
<li class="active">{{aracmarka}}<span class="active"> </span></li>
{{/each}}
</ul>
</div>
<div class="vehicle-nav-control">
<a class="vehicle-nav-scroll" data-direction="up" href="#"><i class="fa fa-chevron-up"></i></a>
<a class="vehicle-nav-scroll" data-direction="down" href="#"><i class="fa fa-chevron-down"></i></a>
</div>
</div>
<!-- Vehicle nav end -->
<!-- Vehicle 1 data start -->
<div class="vehicle-data" id="vehicle-1">
<div class="col-md-6 wow fadeIn" data-wow-offset="100">
<div class="vehicle-img">
<img class="img-responsive" src="img/vehicle1.jpg" alt="Vehicle">
</div>
</div>
<div class="col-md-3 wow fadeInUp" data-wow-offset="200">
<div class="vehicle-price">$ 37.40 <span class="info">rent per day</span></div>
<table class="table vehicle-features">
<tr>
<td>Marka</td>
<td>{{carmark}}</td>
</tr>
<tr>
<td>Model</td>
<td>{{carmodel}}</td>
</tr>
</table>
<span class="glyphicon glyphicon-calendar"></span> Reserve now
</div>
</div>
js
Template.vehicles.helpers({
showcarnames: function() {
return cars.find();
}
});
I would approach this problem using Session. You could target the data using a click event:
Template.vehicles.events({
'click .vehicle-nav li': function(){
Session.set('selected-vehicle', this._id); // or however you id the docs in your app.
}
});
then create an event helper that gets the selected doc and returns it to the template.
Template.vehicles.helpers({
getSelectedVehicle: function() {
var selectedId = Session.get('selected-vehicle');
return cars.findOne(selectedId);
},
});
Session is a great and simple tool to manage user state, like what vehicle they have selected.
Finally, you would then need to get the values in your template somewhere
<!-- html-->
{{#if getSelectedVehicle}}
{{#with getSelectedVehicle}}
<!-- mark up, when using with you can access doc atts directly. -->
{{/with}}
{{else}}
<!-- tell the user to make a selection -->
{{/if}}
using with in this context can lead to more readable markup. But there are other ways to achieve the same result.
To recap, at a high level, You are targeting the users interactions with the UI, to set a global variable as a way to simplify managing state. Be sure to check out Session in the meteor docs, its very simple and powerful. (the above code is not tested, but hopefully conveys the idea)
I'm using bootstrap and attempting to use the panel component for rendering lookup items. It renders perfectly fine, but this was all hand coded.
<div class="row">
<div class="col-md-4">
<div class="panel panel-primary">
<div class="panel-heading">
Item Number 1
</div>
<div class="panel-body">Image Carousel Goes Here</div>
<div class="panel-footer">
<table>
<tr>
<td>Field</td>
<td>Value</td>
</tr>
<!-- etc. -->
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-primary">
<div class="panel-heading">
Item Number 1
</div>
<div class="panel-body">Image Carousel Goes Here</div>
<div class="panel-footer">
<table>
<tr>
<td>Field</td>
<td>Value</td>
</tr>
<!-- etc. -->
</table>
</div>
</div>
</div>
</div>
A JSFiddle is here.
I'm wondering how it'd be possible to do something like:
<div class="row">
#(foreach Item item in items)
{
#RenderItemView(item);
}
</div>
where I could dump all of the "div.col-md-4 ... slash div" code into another cshtml file and use it as a component and just pass the model to it?
I know that I could do this, but would prefer to make this a reusable component.
<div class="row">
#foreach(Item item in items)
{
// instead of using a component, setting the panel-heading off item.Number,
// panel-body by a foreach on item.ImageUrls, etc.
}
</div>
Basically, the subcomponent will be a partial view, I think, but what is the normal way of passing a model to it and it rendering at that spot (basically, like #RenderBody works on layout)
You could create a partial view which holds this content:
#model IEnumerable<ItemType>
<div class="row">
#foreach(var item in Model)
{
// instead of using a component, setting the panel-heading off item.Number,
// panel-body by a foreach on item.ImageUrls, etc.
}
</div>
Save the partial view in the Views/Shared folder, so that it's available everywhere. Then to use it:
#{Html.RenderPartial("YourPartialView", Model.Items);}
function and I want to render an EJS-Partial or a Template with the returned data and finally append it to the DOM. I tried it with
var html = <%- partial('comment') %>"
but this gives me an Error and I tried it with the EJS templates like this
var html = new EJS({url: '/comment.ejs'}).render(comment);
but here I have the problem, that the code doesn't recognize the view folder nor the assets folder where I also tried to copy my partial file into.
Here is the code snippet of my ajax-function
<script>
function postComment(){
if ($('#inputContent').val() != ''){
$.post( "/comment/create/", $('#commentForm').serializeArray(), function(comment) {
//var html = new EJS({url: '/comment.ejs'}).render(comment);
//var html = "<%- partial('comment') %>";
$(html).appendTo('.comments').hide().fadeIn(2000);
$('#inputContent').val('');
});
}
}
</script>
has anyone a solution for my problem? thank you very much
Here's an example that might help to get you where you want to go.
You can put a template in /assets/linker/template directory. The linker directory is created when you create a new sails app using the --linker argument. So, for example, let's say I have a template file called: addUser.ejs with the following code which adds a user to an existing table:
<tr data-id="<%- user.id %>" data-model="user">
<% if (user.online) { %>
<td><img src="./images/icon-online.png"></td>
<% } else { %>
<td> <img src="./images/icon-offline.png"></td>
<% } %>
<td><%= user.id %></td>
<td><%- user.name %></td>
<td><%- user.title %></td>
<td><%- user.email %></td>
<% if (user.admin) { %>
<td> <img src="/images/admin.png"></td>
<% } else { %>
<td> <img src="/images/pawn.png"></td>
<% } %>
<td>Show</td>
<td>Edit</td>
<td><form action="/user/destroy/<%- user.id %>" method="POST">
<input type="hidden" name="_method" value="delete"/>
<input type="submit" class="btn btn-sm btn-danger" value="Delete"/>
<input type="hidden" class="_csrf" name="_csrf" value="<%- _csrf %>" />
</form></td>
</tr>
I can now use that template, in this example, in a separate javascript file contained in /assets/linker/js with the following:
$( 'tr:last' ).after(
JST['assets/linker/templates/addUser.ejs']( obj )
);
So this take the template and uses obj which I passed in with the template to produce the desired html that gets appended in the dom.
edit
In addition, go into Gruntfile.js around line 80 should be the following:
var templateFilesToInject = [
'linker/**/*.html'
];
Change *.html to *.ejs.
Finally, add the underscore.js library to your assets/linker/js directory.
It's also important to have the linker directory structure. I believe the Gruntfile.js are identical whether you use the --linker designation or not, so make a directory off assets called linker with sub directories of js, styles, and templates. Move the existing files under assets/js assets/styles under your new linker directory.