How can I insert a server side handlebars partial using javascript? - javascript

Im building a web application that has some server side layouts and partials. I'm trying to insert partials into the dom using javascript depending on which button the user clicks. Below I've included a simple example that shows what I want to do, obviously it doesn't work. I know you can registerPartials by writing them in the same document and so on, but is there a similar function to be able to use a partial from the server? I wish i could call registerPartial and just pass it the url to the partial or something. For the below example, assume the following folder structure, and that I've registered the partials folder accordingly:
-web
L views
L partials
L edit-user.handlebars
L reset-pass.handlebars
L main.handlebars
code:
<script type="text/javascript">
var edit = {{> edit-user}};
var resetPass = {{> reset-pass}};
$(document).ready(function(){
$("#editMenuAction").click(function(e){
e.preventDefault();
console.log(html);
$("#adminChangesDiv").html(edit);
});
$("#resetPassMenuAction").click(function(e){
e.preventDefault();
console.log(html);
$("#adminChangesDiv").html(resetPass);
});
});
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v3.0.3.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<nav id="menu" class="navbar navbar-default">
<div class="container-fluid">
<!--<div class="navbar-header navbar-brand" id="beingEdited">Admin</div>-->
<ul id="menu-items" class="nav navbar-nav">
<li id="editMenuAction" data-toggle="tooltip" title="Edit this user's profile."><a>Edit Profile <span class="glyphicon glyphicon-edit"></span></a></li>
<li id="resetPassMenuAction" data-toggle="tooltip" title="Reset user's password."><a>Reset Password</a></li>
</ul>
</div>
</nav>
<div id="changesDiv">
</div>

Handlebars won't do http requests for you. I think you have three options:
You could write a small utility function that requests the template, compiles it, and uses it.
Or, if your templates are precompiled, you could consider using requirejs or a similar tool to dynamically load the script.
What I do on my site is precompiled the Handlebars and bundle those functions into my js files which use them, eliminating any latency between when data is ready to be rendered and the actual render.

Related

JavaScript that highlights current day in "hours of operation" part of website

I have a list of the days and hours of operation of a business:
{% load static %}
<link type = "text/javascript" href="{% static 'core/js/index.js' %}">
<div class = "col-md-4">
<div class = "business-hours">
<h2 class="title">Opening Hours</h2>
<ul class="list-unstyled opening-hours">
<li>Sunday <span class="pull-right">Closed</span></li>
<li>Monday <span class="pull-right">9:00-22:00</span></li>
<li>Tuesday <span class="pull-right">9:00-22:00</span></li>
<li>Wednesday <span class="pull-right">9:00-22:00</span></li>
<li>Thursday <span class="pull-right">9:00-22:00</span></li>
<li>Friday <span class="pull-right">9:00-23:30</span></li>
<li>Saturday <span class="pull-right">14:00-23:30</span></li>
</ul>
</div>
</div>
And am trying to use JavaScript so that the current day is highlighted when a user visits the website:
// highlight current day on opeining hours
$(document).ready(function() {
$('.opening-hours li').eq(new Date().getDay()).addClass('today');
});
The above JavaScript is not producing any results and I am not sure why. Note: this is in a Django project with app core, and the JS file is located at core/static/core/js/index.js.
EDIT:
This is the error message shown in the console:
error: Bootstrap's JavaScript requires jQuery
That error message means that either jQuery wasn't loaded, or it wasn't loaded before Bootstrap's JavaScript. You will need to load jQuery before loading the Bootstrap JavaScript file. Your script tags should look something like this:
<link rel="stylesheet" href="bootstrap.min.css">
<script src="jquery.min.js"></script>
<script src="bootstrap.min.js"></script>

Where should I include a script for a view component?

I have tried adding a section script inside a view component's view.
#section scripts {
<script src="~/somepath" asp-append-version="true"></script>
}
I also have the Render Section in the shared layout
#RenderSection("scripts", required: false)
When used in partial views and elsewhere in the project the script loads fine. However when in a View Component the script does not load.
I suppose I could include the script in the section tag of every view that calls the component. I feel this does not fit with the self contained nature of a view component.
Is there another way I can do this?
I also had problems with sections tag in viewcomponents. Turns out, to the best of my knowledge, there is no support for it in viewcomponents. See https://github.com/aspnet/Home/issues/2037
Jake Shakesworth has implemented a tag helper as shown in:
Javascript in a View Component
On the other hand you could just include it in your viewcomponent as an
<script defer src"...">
</script>
My requirement was to show a google map from a viewcomponent. Problem was that the script was getting called before the jquery, jquery.ui stuff.
By using defer you are telling the parser not to execute it until the document had loaded thus avoiding the problem of the having to put it in the layout for proper execution.
Defer is supported by chrome, safari, and ie(10+), ff(3.6+), o(15+)
Hope this helps
This is an example of my code:
#using MobileVet.WebApp.Services;
#inject ISettingsService SettingsService
#{
var Options = SettingsService.Value();
<!--Service Area-->
<div class="container-fluid">
<div class="row p-3">
<!--First column-->
<div class="col-md-3">
<h5 class="title">Site Navigation</h5>
<ul>
<li>Home</li>
<li>Services</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
</div>
<!--/.First column-->
<hr class="w-100 clearfix d-md-none">
<!--Second column-->
<div class="col-md-9">
<div id="map-canvas" style="min-height: 300px; min-width: 200px;">
</div>
</div>
<!--/.Second column-->
</div>
</div>
<!--Service Area-->
<script src="http://maps.google.com/maps/api/js?key=XXXXXXXXXXXXXXXXXXXXXXX&sensor=false"></script>
<script type="text/javascript" src="~/js/components/servicearea.js" defer ></script>
}
Note that you would probably need to write some logic to prevent the script to be included multiple times if the view component is present more than once on a page, which was not my case
From what I have seen, a "#section Scripts {}" in a ViewComponent is ignored and does not render in the relevant #RenderSection() of the ViewComponents _*layout.cshtml
Why that is I do not know.
#section scripts { } in viewcomponents is ignored and not rendered by Asp.Net rendering engine. So just use at the end of the view component. Also if your jquery scripts are specified at the end in your layout, then jquery will not be available in your viewcomponents. Of course moving the jquery script to the head section in layout will solve the problem but it is recommended to load the js files at the end.
So if you want to keep jquery scripts at the end of layout and still use jquery in viewcomponents, you could use javascript domcontentloaded and any jquery can be written inside domcontentloaded. Not a permanent good approach but works for me.
<script>
document.addEventListener('DOMContentLoaded', function (event) {
console.log($ === jQuery)
});
</script>
Or as mentioned by #Alberto L. Bonfiglio you could also try to move your script to another JS file and defer load it in your viewcomponent:
<script src="viewComponentScript.js" defer></script>
This is how I approached inserting scripts into a view component using Asp.net core 2.0.
First I created a partial view which I placed inside of the view components view folder.
Path: Views/Shared/Components/CalendarWidget/_CalendarScriptsPartial.cshtml
_CalendarScriptsPartial.cshtml
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/moment/moment.js"></script>
<script src="~/lib/fullcalendar/dist/fullcalendar.js"></script>
<script src="~/js/calendarWidget.js"></script>
</environment>
<environment exclude="Development">
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/moment/min/moment.min.js"></script>
<script src="~/lib/fullcalendar/dist/fullcalendar.min.js"></script>
<script src="~/js/calendarWidget.js"></script>
</environment>
Then, I brought in the scripts via the Html partial async helper method inside of my view components view.
Path: Views/Shared/Components/CalendarWidget/Default.cshtml
Default.cshtml
<section id="calendar"></section>
#await Html.PartialAsync( "Components/CalendarWidget/_CalendarScriptsPartial" )
And for the sake of completeness here is my view components class.
Path: ViewComponents/CalendarWidgetViewComponent.cs
CalendarWidgetViewComponent.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace LodgersChoice.ViewComponents
{
public class CalendarWidgetViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync( )
{
return View( );
}
}
}
Note: Async isn't currently required in my example but I intend to inject a repository into the ctor of the class which will be using async/await.
Note 2: Once I'm done developing this I plan on bundling and minifying everything down to one script.
I'm registering the ViewComponents scripts in a scoped service, the registered scripts are then rendered after the scripts section in layout.
ViewComponentsService.cs
using System;
using System.Collections.Generic;
namespace YourProject.Services
{
public class ViewComponentsService
{
private readonly List<Func<object>> _scripts = new List<Func<object>>();
public IEnumerable<Func<object>> Scripts {
get {
foreach (var script in _scripts)
{
yield return script;
}
}
}
// A dictionary could be used as type for the _scripts collection.
// Doing so a script Id could be passed to RegisterScript.
// Usefull if only one script per ViewComponent type needs to be rendered.
public void RegisterScript(Func<object> script) {
_scripts.Add(script);
}
}
}
Don't forget to register the service in startup.
services.AddScoped<ViewComponentsService>();
Example ViewComponent
Here we have the ViewComponent and its scripts in the same file!
#model UI.FailUserFeedback
#inject Services.ViewComponentsService _viewComponentsService
#{
var modalId = UI.Utilities.RandomId();
var labelId = UI.Utilities.RandomId();
}
<div class="modal fade" id="#modalId" tabindex="-1" aria-labelledby="#labelId" aria-hidden="true">
#*omitted for brevity*#
</div>
#{
// the script is written here
Func<dynamic, object> RenderScript =
#<script>
(function () {
var modal = new bootstrap.Modal(document.getElementById('#modalId'));
modal.show();
})();
</script>;
// and registered here
_viewComponentsService.RegisterScript(() => RenderScript(this));
}
Layout
#inject Services.ViewComponentsService _viewComponentsService
...
#await RenderSectionAsync("Scripts", required: false)
#foreach(var script in _viewComponentsService.Scripts) {
#script();
}
In case of ViewComponent called by Controller inside a modal or another element being rendered after page is fully loaded, defer won't work either. Instead you must put these scripts in a parent View or in _Layout.
In my case it was an ajax form and
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script src="~/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.js"></script>
or even#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
would not be loaded and caused problems posting the form correctly.
View component in ASP.NET Core acts like independent view with separated controller, so you can insert bellow tag above of your view component
#{
Layout = null;
}
after that insert bellow tag to use related script,for example:
<environment include="Development">
<script src="~/js/chart.js"></script>
</environment>
<environment exclude="Development">
<script src="~/js/chart.min.js"></script>
</environment>

How do get JQuery to work when I am using AngularJS partials?

I have the below code. However, my JQuery wont run when the #id and .classes it is looking for are in partials when viewing this static page. How do I get it to work?
<body ng-app>
<h2>JQuery wont run if code it is looking for is in a Partial</h2>
<div ng-include="'_includes/partials/menu.html'" ></div>
<br />
<h2>JQuery will work if the code it is looking for is here on the page (DOM)</h2>
<div class="container">
<div class="row">
<div class="col-xs-12">
<ul class="nav">
<li><a>Home</a></li>
<li><a>About</a></li>
<li><a>Services</a></li>
</ul>
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="_includes/scripts/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script src="_includes/scripts/custom.js"></script>
</body>
It is not a good practice to try to find html elements and modify them in an AngularJS app as you would normally do in a JQuery enabled html. Instead, try to implement whatever you are thinking of only using Angular.
Anyway you want to use ng-directives instead jQuery calls.

JavaScript: print working directory, list files in subdirectory to console

I'm new to JavaScript, and am working on a website where you can upload files and display a result summary.
I've successfully uploaded the results to the webpage / on the server.
However, I am having trouble reading in an uploaded HTML file from the server ,to load the HTML file and display it.
Below is the HTML script which prints the path to the HTML file. but how to load the HTML i.e. run the HTML file using javascript??
<!doctype html>
<html>
<head>
<title>Summary Report</title>
<link rel="stylesheet" type="text/css" href="https://da1s119xsxmu0.cloudfront.net/libraries/basestrap/1.0.0/css/master.min.css" />
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="col-xs-12">
<h3>Summary Report</h3>
<h4>App Results:</h4>
<ul>
<h3>{{ result.name }}</h3>
<h4>Result Files:</h4>
<ul>
{% for key in result.files %}
{% if key contains '.html' %}
<li>{{ key }}</li>
</ul>
</div>
</div>
</div>
</body>
</html>
Output
The output is an unordered list of the html file on the server that I need to be read into the screen console.
1662b5e25a574e89abf2a5490005585a/expressionCSV/limmaWithMeta.html
What is your backend running? node.js? HTML/client side JavaScript isn't going to help you list the files uploaded to the server. You should include the code that populates session.results.
In general, based on what you've mentioned about the current behavior, I'd suggest that you use a recursive function to traverse the subdirectories:
function listTree(root) {
print(root);
if (root.isDirectory()) {
root.getFiles().forEach(function(file) {
listTree(file);
});
}
}
As mentioned above, this would go in the server side code since that's where the files are actually stored. (Your users' computers shouldn't be able to access all the files on the server, right? :) )

Can't Enter Main Function in HoverIntent

My project consists of a menubar, and I would like to have the submenus display below when the mouse hovers over each button (hoverIntent). I am using the Wet-Boew (Web Experience Toolkit) (https://github.com/wet-boew/wet-boew) to create these features.
My project workspace consists of a main project php folder, including an index file which calls a jquery.min.js and subsequently the hoverintent.js and menubar.js.
Below is the start of the hoverintent.js:
(function($) {
// Alert Point A
$.fn.hoverIntent = function(f,g) {
// Alert Point B
// default configuration options
var cfg = {
sensitivity: 7,
interval: 100,
timeout: 0
};
// override configuration options with user supplied object
cfg = $.extend(cfg, g ? { over: f, out: g } : f );
etc...
})
My problem is that although I can reach the first alter point A I have in my code (and can generate the alter box), the program won't run the $.fn.hoverIntent = function(f,g){...} (where I have the second Alert Point B). I have a similar problem with my menubar.js (where the main functions of the code won't load).
What is usually the most common source of this problem and the best way to fix it?
It should be noted that I do call a jQuery earlier on in a different php project folder (still inside the project workspace) that has to do with a separate login program for this software. The Index file jumps to the login program to get the user's credentials before returning to the index document to display the main content.
I made sure this was the same jQuery file I later referenced in the index file before the hoverintent.js and menubar.js. Is this what is causing the issue?
Sorry I don't have all the code at this time to share, I will try to get the rest out soon. Thanks in advance.
----------------UPDATE-------------------------------
My main index file includes the head with the following code. Note the "../" are required since the wet-boew project folder is seperate from the main program project folder (index) in the workspace:
<head>
<script src="../wet-boew-master/build/js/jquery.min.js" type="text/javascript"></script>
<script async="async" src="../wet-boew-master/build/js/dependencies/outside-min.js"></script>
<script async="async" src="../wet-boew-master/src/js/dependencies/hoverintent.js"></script>
<script async="async" src="../wet-boew-master/build/js/dependencies/equalheights-min.js"></script>
<script async="async" src="../wet-boew-master/build/js/dependencies/resize-min.js"></script>
<script async="async" src="../wet-boew-master/build/js/i18n/en-min.js"></script>
<script src="../wet-boew-master/src/js/workers/menubar.js" type="text/javascript"></script>
<title>Title of the Project</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<link rel="icon" type="image/ico" href="images/icon.ico">
<script src="../wet-boew-master/build/js/settings.js"></script>
<link href="../wet-boew-master/build/grids/css/util-min.css" rel="stylesheet"/>
<link href="../wet-boew-master/build/js/css/pe-ap-min.css" rel="stylesheet"/>
<link href="../wet-boew-master/build/.../css/theme-min.css" rel="stylesheet"/>
<noscript><link rel="stylesheet" href="../wet-boew-master/build/.../css/theme-ns-min.css" /></noscript></head>
Further down, inside the body of the index we have the menubar:
<body>
<div id="wb-body">
<div id="wb-head">
<div id="wb-head-in">
<header>
<div id="wu-bnr" role="banner">
<nav role="navigation">
<div id="wu-psnb" >
<div id="wu-psnb-in">
<div class="wet-boew-menubar mb-mega" data-load="menubar" role="application" style="min-height: 28px;">
<div>
<ul data-ajax-replace="../wet-boew-master/demos/includes/menu-eng.txt" class="mb-menu" role="menubar">
At which point my menubar options and their respective submenus are listed as such:
<li *class=""* role="presentation">
<section role="presentation">
<h3 role="presentation">
<a href="index.php?location=activitiesMenu:index" role="menuitem" class="knav-1-0-0 mb-has-sm" aria-haspopup="true">
<span class="expandicon">
<span class="sublink"><?=$glb_string["activities"]?></span>
</span>
<span class="wb-invisible">(open the submenu with the enter key and close with the escape key)</span>
</a>
</h3>
<div *class="mb-sm"* role="menu" *aria-expanded="false"* *aria-hidden="true"* **id="myHoverIntent"**>
<div class="span-2" role="presentation">
<ul role="presentation">
<li role="presentation"><?=$glb_string["views"]?><?=($language_set_variable == 'fr'?:)?></li>
<li role="presentation"><?=$glb_string["create"]?><?=($language_set_variable == 'fr'?':')?></li>
</ul>
</div>
</div>
</section></li>
Would this be the correct location for my id="MyHoverIntent" (Bold **) in the code above?
It should also be noted that the italic code (*) above isn't changing (I'm assuming because the menubar and hoverIntent main functions aren't running). This would normally auto-update as the user hovers over each menubar option or leaves it. I know this because of the sample file that was included in the WET-BOEW folder that shows a fully functioning page (with a menubar and hoverIntent working) and these changes were observed in Firebug. Although for some reason Firebug showed that the sample never referenced menubar.js.
It's a little hard to tell what exactly you are doing that stops your code from working since we only have half of the code right now but a few things come to mind. First, the hoverIntent function will get called when you actually call it on a jQuery Object like so
$('#myHoverIntent').hoverIntent();
Second, make sure you are not doing that before the hoverIntent function actually gets defined and lastly, make sure you are passing window.jQuery into your immediately-invoked function expression
Here is a fiddle of a working example: http://jsfiddle.net/G3vCS/

Categories

Resources