I have an MVC 4 site with an area. I setup two script bundles, one for all common scripts the site will need and the other for scripts related to area. I have a common layout view for the site where the common site bundles are referenced using Scripts.Render(). I have a second layout view for the area, which uses the common layout view, where I would like to render the area-specific javascript files, but it does not work and no files are rendered at all. If I move the bundle render to the root layout view, it renders fine.
Any reason why this does not work in the area view and how I can get it to work? I'd rather not have these area-specific scripts available for all users, since only a very small, defined subset actually need them.
Common Layout View:
#Scripts.Render(#"~/Scripts/all_scripts")
...
#RenderSection("Javascript", required: false)
Area Specific View:
#section Javascript {
#Scripts.Render(#"~/Scripts/area_scripts")
#RenderSection("Javascript", required: false)
}
I tested this and it appears to be working fine. Admin specific scripts are rendered in the admin index view (and works in the admin layout too). Are all the bundles/paths configured correctly?
BundleConfig.cs
bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
"~/Scripts/jquery-ui-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryadmin").Include(
"~/Scripts/Admin/jquery.unobtrusive-ajax-admin*",
"~/Scripts/Admin/jquery.validate-admin*"));
_Layout.cshtml
#Scripts.Render("~/bundles/jqueryui")
#RenderSection("Javascript", required: false)
_AdminLayout.cshtml
#{
ViewBag.Title = "_AdminLayout";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>AdminLayout</h2>
#section Javascript{
#RenderSection("Javascript", required: false)
}
AdminHome/Index.cshtml
#{
ViewBag.Title = "Index";
Layout = "~/Areas/Admin/Views/Shared/_AdminLayout.cshtml";
}
<h2>Index</h2>
#section Javascript{
#Scripts.Render("~/bundles/jqueryadmin")
}
Hope this helps.
Related
So I'm working a project of a Website. In it, there's an admin page where I can add or remove images that will be shown on the website. I created a Controller for the Main Admin page alone, and then I created a controller for every type of information that can be changed through that page (Porfolio, banner, etc). All the pages are styled by CSS. So when my AdmController returns the view with the main Admin page, everything works fine
The adress for the main Admin Page results in localhost:8000/adm
But once I try to open a view where I would add an image to be shown on the Main page, CSS simply won't work. To acess, say, the add banner page, I have a BannerController that will return a "form-banner" view, resulting in the adress localhost:8000/adm/banner. In this page CSS does not work.
I wanted to test further so I created a new Route that would take me directly to the create banner page without going through the admin page, and also not using any Controllers at all. I got the adress localhost:8000/banner. Now CSS works.
Any ideas why?
These are the routes including the one I created just to test the view:
Route::resource('adm', 'AdmController');
Route::resource('adm/banner', 'BannerController');
Route::get('banner', function () {
return view('admin/form-banner');
});
This is the AdmController:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdmController extends Controller
{
public function index()
{
return view('admin/index');
}
}
This is how the BannerController is returning the mal-functioning View:
public function create()
{
return view('admin/form-banner')
And this is the point in the Main Adm View (the one that works) where It calls the BannerController:
<ul class="nav-second-level" aria-expanded="false">
<li>Create new banner</li>
Add your CSS like below
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
the absolute path after your public folder
In ASP.NET, we have Application Settings, and we have Application Pre/Post Build Events. Is it possible to access a Setting from the Pre Build Event? Or is it possible to inject the value of a Setting from the Pre Build Event?
Full context:
I have an Angular app embedded in an ASP.NET 4 Web API app. That is, my app is structured like this:
+ Solution
| - Project
| + Properties
| + AngularApp
| | + dist
| | + e2e
| | + src
| | - (etc)
| + App_Start
| + Model
| + Global.asax
| - Web.config
- ProjectTest
I have some URL rewrite rules so that any request website.com/x that doesn't refer to one of my Controllers will instead be redirected to website.com/AngularApp/dist/AngularApp/x. Everything I've described so far is working great.
The trouble is, this app is not being deployed to the root of the domain; it's being deployed to a subdirectory of the domain. (i.e. website.com/app instead of website.com). Three different portions of my app need to know that this new subdirectory should be considered root - the Angular app needs to have this configured as root, the rewrite rules need to incorporate this, and a certain pieces of C# code also needs to know about this new root (I'll save you the details here). Currently, I've had to specify this subdirectory in both the Pre Build Events (which are building the Angular app) and the Web.config (which controls my rewrite rules) and the Settings (which are accessed by my aforementioned C# code). It'd be better if I could have a single configuration that they all pulled from. My above question would at least allow the combination of two of these disparate three configurations.
My suggestion is not to do with any build events, it's rather to bootstrap your angular app with some values from hosting ASP view.
If I understand your app layout correctly, you might be able to push some variables onto a Razor view as plain javascript that would get picked up by Angular upon startup.
Model
public class SampleViewModel
{
public string Path { get; set; }
}
Controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View(new SampleViewModel() { Path = "/app/1/test" });
}
}
View
#model HelloWorldMvcApp.SampleViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
</head>
<body>
<h1>Server-side path #Model.Path</h1>
<hr/>
<div ng-app="myApp">
<div ng-controller="MyController">
<h1>{{message}}</h1>
</div>
</div>
<script type="text/javascript">
var clientSidePath = "#Model.Path"; #* Razor happily renders values into javascript blocks *#
var app = angular.module('myApp', []);
app.controller('MyController', function($scope) {
$scope.message = 'Client-side path ' + clientSidePath;
});
</script>
</body>
</html>
The absolute minimum Dotnet fiddle here: https://dotnetfiddle.net/pO2wHN. For simplicity sake I opted for AngularJS (which is probably not the exact version you use) but similar approach should work with recent Angular as well.
I use DataTables in some specific tables and it needs at least 10 different js/css files to work in my situation. So i tried to put them in a bundle and called that bundle in that view. But no success.
My question is that: Are bundles only for entire site (loads in every page) or can i use some of them in specific views only?
BundleConfig
bundles.Add(new ScriptBundle("~/Content/DataTablesJS").Include("~/Content/DataTables/*.jss"));
bundles.Add(new StyleBundle("~/Content/DataTablesCSS").Include("~/Content/DataTables/*.css"));
View
#section Styles
{
#Scripts.Render("~/Content/DataTablesCSS")
}
#section Scripts
{
#Scripts.Render("~/Content/DataTablesJS")
<script src="~/Content/SayfaJSs/DataTables.jss" type="text/javascript"></script>
<script>
jQuery(document).ready(function() {
DataTables.init();
});
</script>
}
HTML Output
<script src="/Content/DataTablesCSS?v=z-Ctaq2TbplDFpORl0e9NGH8TjpB5hQ2cPam2OxmDEo1"></script>
<script src="/Content/DataTablesJS?v=2gXGKlcqr0bFFqv6Bbr9jB_7LVvvHDrghzBwHCgFJds1"></script>
In your layout you would have something like this:
#RenderSection("Scripts", required: false)
...Then in your view you would add your bundle reference like this:
#section Scripts {
#Scripts.Render("~/bundles/yourBundle")
}
I found the problem. It was using asterisk to get all scripts in folder. From asp.net website:
"Adding scripts by wildcard defaults to loading them in alphabetical order, which is typically not what you want. "
My scripts needs a special order. So i included them in order that i need:
bundles.Add(new StyleBundle("~/Content/DataTablesCSS")
.Include("~/Content/DataTables/dataTables.bootstrap.css",
"~/Content/DataTables/buttons.dataTables.min.css",
"~/Content/DataTables/select.dataTables.min.css"));
bundles.Add(new ScriptBundle("~/Content/DataTablesJS")
.Include("~/Content/DataTables/jquery.dataTables.min.js",
"~/Content/DataTables/dataTables.bootstrap.js",
"~/Content/DataTables/dataTables.buttons.min.js",
"~/Content/DataTables/dataTables.select.min.js",
"~/Content/DataTables/buttons.bootstrap.min.js",
"~/Content/DataTables/jszip.min.js",
"~/Content/DataTables/pdfmake.min.js",
"~/Content/DataTables/vfs_fonts.js",
"~/Content/DataTables/buttons.html5.min.js",
"~/Content/DataTables/buttons.print.min.js"));
I'm trying to get a breadcrumb navigation to show up just below my main navigation in a NopCommerce theme, so the code to show it needs to be in Views/Shared/header.cshtml, but having it there causes pages that aren't categories to break. Is there any way to do "if is category page, execute code" in nopcommerce? I can't find any good source of documentation for this platform...
Here's my breadcrumb code if it matters:
#if (Model.DisplayCategoryBreadcrumb) {
<nav class="plain">
<ul>
<li>#T("Categories.Breadcrumb.Top")</li>
#for (int i = 0; i < Model.CategoryBreadcrumb.Count; i++)
{
var catBr = Model.CategoryBreadcrumb[i];
<li>#catBr.Name</li>
}
</ul>
</nav>
}
Thanks!
I can't find any good source of documentation for this platform...
nopCommerce runs on MVC, so anything that works in MVC works for nopCommerce too.
Which brings is to MVC basics. You can try go get info about current request (such as current Controller) by using the ViewContext or RequestContext whichever is relevant. For example, you can try to get the current controller by using:
#{
var controller = ViewContext.Controller;
}
:)
I was hoping anyone could give some input on this,
I'm creating a meteor app in which I would like to use bootstrap to creating the admin environment, but have the visitor facing side using custom css. When I add the bootstrap package to my app using meteor it's available on every page, is there a way to restrict the loading of bootstrap to routes that are in '/admin' ?
When you add bootstrap package it's not possible. You can, however, add bootstrap csses to public directory and then load them in a header subtemplate that will only be rendered when you're in the dashboard.
EDIT
But then how would you go about creating seperate head templates?
Easy:
<head>
...
{{> adminHeader}}
...
</head>
<template name="adminHeader">
{{#if adminPage}}
... // Put links to bootstrap here
{{/if}}
</template>
Template.adminHeader.adminPage = function() {
return Session.get('adminPage');
}
Meteor.router.add({
'/admin': function() {
Session.set('adminPage', true);
...
}
});
DISCLAIMER: I am unsure of a 'meteor way' to do this, so here is how I would do it with plain JS.
jQuery
$("link[href='bootstrap.css']").remove();
JS - Credit to javascriptkit
function removejscssfile(filename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist from
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(filename)!=-1)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
}
removejscssfile("bootstrap.css", "css")
However, doing that would complete remove it from the page. I am not sure whether meteor would then try to readd it when a user goes to another page. If that does not automatically get readded, then you have an issue of bootstrap not being included when someone goes from the admin section to the main site, which would break the look of the site.
The way I would get around that would be to disable and enable the stylesheets:
Meteor.autorun(function(){
if(Session.get('nobootstrap')){
$("link[href='bootstrap.css']").disabled = true;
}else{
$("link[href='bootstrap.css']").disabled = false;
}
});
There my be other bootstrap resources which may need to be removed, take a look at what your page is loading.
To use jQuery in the same way but for the javascript files, remember to change link to script and href to src
From my tests, Meteor does not automatically re-add the files once they have been removed so you would need to find some way of re-adding them dynamically if you want the same user to be able to go back and forth between the main site and the admin site. Or simply if the http referrer to the main site is from the admin, force reload the page and then the bootstrap resources will load and everything will look pretty.
P.s. make sure you get the href correct for the jQuery version
If somebody is interested in including any js/css files, I've written a helper for it:
if (Meteor.isClient) {
// dynamic js / css include helper from public folder
Handlebars.registerHelper("INCLUDE_FILES", function(files) {
if (files != undefined) {
var array = files.split(',');
array.forEach(function(entity){
var regex = /(?:\.([^.]+))?$/;
var extension = regex.exec(entity)[1];
if(extension == "js"){
$('head').append('<script src="' + entity + '" data-dynamicJsCss type="text/javascript" ></script>');
} else if (extension == "css"){
$('head').append('<link href="' + entity + '" data-dynamicJsCss type="text/css" rel="stylesheet" />');
};
});
}
});
Router.onStop(function(){
$("[data-dynamicJsCss]").remove();
});
}
Then simply use:
{{INCLUDE_FILES '/css/html5reset.css, /js/test.js'}}
in any of your loaded templates :)