3

I need some advice.
(For those who have already read this before I have re-edited this question heavily)

I have developed some asp.net mvc web pages.
Each page has a master and some ascx controls (between 2 - 6) embedded into it a js and css file.
Up to now every thing was fine.

In order to improve modularity, flexibility and testability the ascx's are now expected to be able to work as stand alone controls.
(Each ascx has also got its own css and js files in some cases it has another control inside it)

In order to meet this requirement we call the controller with a query string.
(Different from the manner that it is called from the page - via Ajax)

The rendered ascx (partial) is presented in the browser without all of the other parts of the original page .

In this case, in order to get the partial to display correctly (css) and act correctly (js/jquery) all of the relevant files need to be added (for example: jquery) to the user control.
This contradicts the concept of positioning the files in the most logical place (could be the master page for example).

How can I overcome this problem? Keep in mind that this is relevant for each "control" ascx file that is created in the application.


Examples:
I have added a description of 3 cases that will depict my scenario:
(this has been copied from another question I asked here).

Case 1: In the page case it could be that a page has a few partials that are loaded using ajax while the page is being built. The partials might be called again using ajax according to the users actions. In this case I consider them as controls on a page.

Case 2: In the stand alone case the partial could be called as part of a test directly from the browser. In this case you only see the partial part in the browser.

Case 3: In the third case the partial could be called as part of an iframe within a google chrome extension (for example). In this case you can see the partial in a page that might not have been built in your web application.


Any thoughts will be appreciated.

For those that celebrate - Happy new year!

Community
  • 1
  • 1
  • julian, i would 'submit' that the css is irrelevant to the proper functioning of the control. why?? because the css is directly linked to the overall look and feel of the target site in question. therefore, in my opinion, the css (unless related to jquery selectors) should by abstracted at a higher level and therefore completely isolated from the ascx controls in question. i may be wrong but this feels more 'right' to me - i.e. css driven by site, rather than functionality of control (except where the css is jquery driven class or id selectors). – jim tollan Dec 29 '10 at 18:49
  • ran out of characters to complete :). using the above discipline means that both admin and public facing controls can be shared, even if the styling on both are at odds with each other. – jim tollan Dec 29 '10 at 18:53
  • @jim - some of our controls contain in them hidden elements (using css) If the css is at site level the hidden fields will be seen on the control when it is rendered alone. In addition the user can not validate the look and feel of this control if no css is in place. –  Dec 29 '10 at 18:58

2 Answers2

2

If you need to add content to the hosting page, you can have code in your .ascx file to do this server-side. For example:

<%
  var link = new HtmlLink { Href = Url.Content("~/Content/Style/MySheet.css") };
  link.Attributes["rel"] = "Stylesheet";
  link.Attributes["type"] = "text/css";
  Page.Header.Controls.Add(link);
%>

For this example to work, you must have a runat="server" for your head tag.

Jacob
  • 77,566
  • 24
  • 149
  • 228
  • thanks, I have about 15 files to include in order to get the control to work stand alone. (jquery, microsoft, theme file etc..) is there a way to distinguish between when the control is part of a web page or run stand alone and in that case include your code for the relevant (15) files? –  Dec 29 '10 at 19:03
  • Since you have your controller handling the logic of rendering just the partial, it could pass data to the View Model of the partial to let it know whether it should render as an entire page rather than just a piece. – Jacob Dec 29 '10 at 19:12
  • I do not think that the controller should be aware of the "mode" it is being called by. –  Dec 29 '10 at 19:35
  • Then what do you mean by "In order to meet this requirement we call the controller with the relevant parameters and it returns the ascx (partial) directly to the browser without all of the other parts of the original page."? If you're passing parameters to the controller to tell it to render standalone, then the controller knows its mode. – Jacob Dec 29 '10 at 19:38
  • the user control in some cases has a query string that pass keys for linq selects. What i understand from your question is that it might be worth adding an additional parameter to indicate the "mode" of work. I need to think about this a bit. –  Dec 29 '10 at 20:17
0

I am adding my own answer, it might be that my question was not clear enough. In any case if someone needs a solution this is where I am at the moment:


This is the bottom section of the partial (Control)

<%--
///-----------------------------------------------------------------------
/// <summary>
///     <title>Java Scripts Section</title>
///     Contains all links to java script files that are used by this
///     partial.
///
///     If the partial is part of a viewpage, only the partial's scripts
///     should be downloaded. (It was called using Ajax)
///
///     In the case that the partial acts as a stand alone control it needs
///     to fetch other scripts that are preloaded by the application.
///     (For example jQuery)
///
///     This is achived by identifying that the partial was not called
///     via Ajax in this case the list of Java Script files that have
///     been included is added to the HTML that then fetches them from
///     the server.
///     <ToDo>
///         A. Need to join and minify scripts to improve performance.
///         B. Consider identifing the Ajax call in the controller:
///            request.IsAjaxRequest().
///     </ToDo>
/// </summary>
///-----------------------------------------------------------------------
--%>
<%
    string areaRoot = "~/Areas/Manufactor/";
    string areaJsRoot = areaRoot + "JQuery/";

    string dataLayer = areaJsRoot + "manufactorAjax.js";
    string javaScript = areaJsRoot + "vucManufactorDetails.js";    
%>
<% if (HttpContext.Current.Request.Headers.Get("X-Requested-With") != "XMLHttpRequest") {  %>
<!-- #Include virtual="~/Include/GenericScripts.inc" -->

<script type="text/javascript" src="<%= ResolveUrl(dataLayer)%>">
</script>
<% }; %>

<script type="text/javascript" src="<%= ResolveUrl(javaScript)%>">
</script>
<%--
///-----------------------------------------------------------------------
/// <end>
///     This ends the ManufactorDetails.ascx file.
/// </end>
///-----------------------------------------------------------------------
--%>

This is the content of the include file:

<%--
///-----------------------------------------------------------------------
/// <summary>
///     <link>System generic Scripts</link>
///     The system generic scripts used to manage controls in the system.
/// </summary>
///-----------------------------------------------------------------------
--%>

<%
    string jsRoot = "~/Scripts/";

    string jqueryLink = jsRoot + "jquery-1.4.1.min.js";
    string jqueryUI = jsRoot + "jquery-ui-1.8.4.custom.min.js";
    string jqueryCorner = jsRoot + "jquery.corner.js";
    string microsoftAjax = jsRoot + "microsoftAjax.js";
    string microsoftMvcAjax = jsRoot + "microsoftMvcAjax.js";
    string dataProvider = jsRoot + "dataProvider.js";
%>

<script type="text/javascript" src="<%= ResolveUrl(jqueryLink)%>">
</script>

<script type="text/javascript" src="<%= ResolveUrl(jqueryUI)%>">
</script>

<script type="text/javascript" src="<%= ResolveUrl(jqueryCorner)%>">
</script>

<script type="text/javascript" src="<%= ResolveUrl(microsoftAjax)%>">
</script>

<script type="text/javascript" src="<%= ResolveUrl(microsoftMvcAjax)%>">
</script>

<script type="text/javascript" src="<%= ResolveUrl(dataProvider)%>">
</script>

<%--
///-----------------------------------------------------------------------
///     End of GenericScript.inc
///-----------------------------------------------------------------------
--%>

I have applied similar logic for css files at the top of the partial.

Note:
The include file is always loaded. In the case of the partial - that is part of the web application it is not processed.

Be happy and enjoy life, Julian