Link to home
Start Free TrialLog in
Avatar of Robb Hill
Robb HillFlag for United States of America

asked on

Inserting Javascript on VIEWS globally with exclusions

I have an MVC layout page.


I am looking to do the following and am not quite sure how to do this.  I am hoping someone has had to do this before.


So I have a  3rd party I am integrating to our website that will have a javascript file that will need to go on many of our views but not all.   I would like to setup something at the main layout page that will check a config file or database table for the views it should exclude then Render some script on the views not exluded that is the same on every page.


For now the limit to my question is MVC but my website has a Master page from ASPX to that I wlll need to add to my solution.


It also has an angular spa.  Currently for the Angular spa I am trying to determine if we would just care about the spa or that actual flows within it.  I am leaning to the flows.


Eitherway If I can get something working on MVC as a POC that would help alot.


I was thinking you might have something on the layout like so


@If(Global.Current.Page(ViewName)

@ScriptRender("~/location")


Obviously that needs work but just my general idea.

Avatar of Kelvin McDaniel
Kelvin McDaniel
Flag of United States of America image

I've accomplished something like this using sections, with overrides to ignore the section on specific pages.

The key for your scenario is to use the IsSectionDefined feature (in your master page) to provide the 3rd party content. This gives you the default global inclusion.

Then -- on a given page where you don't want the content to be included -- add the @section call and put something there that will override the master page content. I can't remember if you can simply leave it empty or not. Regardless, that will exclude the 3rd party content from the view in question.

In the examples below I'm calling the section specific_3rd_party_script so that it's easier to see and understand what I'm doing with it.

Master Page -- add the following where you want it to render in your HTML (probably at the bottom of the page):
@if (IsSectionDefined(“specific_3rd_party_script”))
{
  @RenderSection(“specific_3rd_party_script”, required: false)
} 
else
{
  <script>
    // this is your 3rd party script. You can use the src attribute instead if you prefer.
  </script>
}

Open in new window


View Page where you want to exclude the specific_3rd_party_script content -- add the following:
@section specific_3rd_party_script {
  <script>
    // purposely exclude this content
  </script>
}

Open in new window

Avatar of Robb Hill

ASKER

I like this but this is a public facing site with alot of pages.   I was hoping to not have to touch every view if possible.
Thus the reason I indicated maybe a config or db call that only sais to test what is an exclusion.

Also would bottom of page be ok...in this  case this javascript that is loaded is a script that adds content to the header of any page its loaded on.
ASKER CERTIFIED SOLUTION
Avatar of Kelvin McDaniel
Kelvin McDaniel
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
this is very helpful!!!!

I think due to the massive website this is I would need controller name in the route..

for example you could have many index pages.

I also have to do this same implementation on aspx pages in the site...so the master page.

and angular.

We have some of all in the site.  
Depending upon the version of .NET and MVC you're using (4.7.x, 5, 6, etc.), adding the controller is simple.

Ultimately, you'll just need to debug the Context.Request.RouteValues collection to see what/how the controller name is provided, and then update your check to include it. For the sake of discussion let's assume that RouteValues includes an entry for "controller".

My suggested updates (again, you'll need to debug this and adjust it based on the version of .NET MVC you're using) are below.

var routeIsNotExcluded = true; // default value
var controller = (string)this.Context.Request.RouteValues["controller"];
var action = (string)this.Context.Request.RouteValues["page"];
var config = Configuration.GetSection("ExcludedRoutes")?.GetChildren();
if (config != null)
{
  // we assume that the Controller entry does not include a leading slash.
  // we know from testing that the Page entry includes a leading slash.
  routeIsNotExcluded = config.All(x => x.Key != $"/{controller}{action}"); 
}

Open in new window

yea....the hangup I am having now is how to add this to a spa where this script should be loaded not by the page but by the event(s) in the spa.


Any idea how to do that.

Yep, there area few different techniques I've used in the past. If you're using Router then it gets easier to know what route you're testing.

1. Transport the configuration over to the spa as a JavaScript property. Basically, write an extension method that returns the configuration entry (ExcludedRoutes) as an enumerable, then set that on the page which loads the spa. Pull that in as a global variable (terrible, I know), and then use that for your checks.

2. Create a webservice call that does the same check and returns a boolean. Use that in the spa. This one is typically the easiest and cheapest in terms of application "weight".
Im still banging my head on the angular.  

But How do we do this with a MasterPage.   So again similar but very different that the MVC.  I will use the same appsettings.config to store all this for all page types.

However I want to be able to control the masterpage from config and so far I am only seeing how to do this progromattically on every content page.   Any ideas?


Thanks again for the great help!
Just to make sure we're on the same page (no pun intended), the MasterPage has nothing to do with Angular other than influence the page that initially loads the spa or spa page (if you're going individual pages instead of a traditional spa). The hosting page won't change its rendered HTML in any way that Angular can take advantage of.

I hope what I just said is clear.

When I get into a situation like what you're attempting to address, I create a centralized component and add that component to my pages. One way or the other, I think you're going to have to touch each of your associated Angular pages at least once. 
We have a big website with Angular 12, mvc , and webforms.
Ouch -- I feel that pain. There might be some hook that you can exploit/co-opt/repurpose and couple that with a TypeScript base class to give you that across-the-board-with-as-few-touches-as-possible support you're looking for. You'd basically need to do your check in the base class constructor and go from there. I have no idea how all that would play out though, and I'm sure that strategy would need to be tweaked significantly.

Sorry I couldn't be more help; good luck!