-
Notifications
You must be signed in to change notification settings - Fork 9
Customizing Views
In this guide I will cover the following topics
Exico Shopify Framework uses bootstrap CSS framework for styling its views. The views are razor cshtml files pre-compiled into the framework as dll. Almost each and every views that are rendered by the framework can be replaced by your own custom razor view. Each view is composed of a parent and several child views.So to change an entire page (parent view) or a single child view within the parent view all you need to know is the view name.Then create that view in your app's views\shared directory and you are done.
Now the question is how do you know the name of the view! There are two ways to know the view name
All view names are listed in the ViewNames class in the ViewBagClasses.cs file.
Below is the content of the class
public class ViewNames
{
public const string SCRIPT_SECTION = "scripts";
public const string STYLE_SECTION = "styles";
public string ErrorPage = "XError";
public DashboardViews Dashboard { get; set; } = new DashboardViews();
public MetaViews Meta { get; set; } = new MetaViews();
public MyProfileViews MyProfile { get; set; } = new MyProfileViews();
public ShopifyViews Shopify { get; set; } = new ShopifyViews();
public WebMsgViews WebMsg { get; set; } = new WebMsgViews();
public NavBarViews NavBar { get; set; } = new NavBarViews();
public AccountViews Account { get; set; } = new AccountViews();
public LogoViews Logo { get; set; } = new LogoViews();
public HomeViews Home { get; set; } = new HomeViews();
public FooterViews Footer = new FooterViews();
}
An instance of this ViewNames class is available in any controller that inherits the Exico.Shopify.Web.Core.Controllers.BaseControllers.ABaseController class and also available in the ViewBag.Views variable during run time.
Let's go over a small exercise of finding out the view name of the My Profile index page. Let's say we need to customize the My Profile index view.And If you haven't changed anything in the settings then the default controller for rendering profile page is MyProfile. Now Let's go back to the class ViewNames in file ViewBagClasses.cs where view names are listed and find out a class property that matches with the profile rendering controller name.If you look closely you will see a object type property called MyProfileViews.Now jump to the definition of the MyProfileViews class (in the same file ViewBagClasses.cs), the content looks like this
public class MyProfileViews
{
public string Index { get; set; } = "MyProfileIndex";
public string IndexDefaultContent { get; set; } = "_MyProfileIndexDefaultContent";
public string IndexOptionalContent { get; set; } = "_MyProfileIndexOptionalContent";
public string ChangePlan { get; set; } = "MyProfileChangePlan";
}
In that above class you can see few string properties, these property values directly correspond to a single view name. Any value that starts with underscore is a child view, that is it is being called and rendered inside another view (parent view). We see a property called Index it means that this is the Index action's parent view name. Then we see two more properties that has the word Index in them ; IndexDefaultContent and IndexOptionalContent. This means that Index has two children. IndexDefaultContent renders the default content and then IndexOptionalContent is called to render optional content(if available).
Now back to our exercise, if we we want to replace the default content of the My Profile's Index action content then we create a view called _MyProfileIndexDefaultContent.cshtml inside our views\shared directory and we will be done. But we we want to have the default content but add another section after that than we create a view _MyProfileIndexOptionalContent.cshtml in the views\shared directory and system will render it after rendering the _MyProfileIndexDefaultContent.cshtml view. And lastly if we want to completely change the layout and content for the _MyProfile's Index action then we create a view called _MyProfileIndex.cshtml inside the same views\shared directory.Now if we run the app and try to access MyProfile\Index then our view will be loaded instead of the system default.
When the app is installed on a store for the first time and you access it from store admin, it takes you to dashboard\index and you see this view
Well this page already tells you do create a view called _DashboardIndexDefaultContent.cshtml in that views\shared directory to replace the content. We can blindly do that or we can dig a little deeper. Let's pretend that we do not know the name of the view. Let's do it step by step to find it out
-
Open file and find the ViewNames class
-
Look for the property name starts with **Dashboard ** (the controller name)
Aha! found it
public DashboardViews Dashboard { get; set; } = new DashboardViews();
-
Now let's find the the definition of class DashboardViews
-
Aha found that one too!! In the same ViewBagClasses.cs file
public class DashboardViews
{
public string Index { get; set; } = "DashboardIndex";
public string IndexDefaultContent { get; set; } = "_DashboardIndexDefaultContent";
public string IndexOptionalContent { get; set; } = "_DashboardIndexOptionalContent";
public string PlanDoesNotAllow { get; set; } = "DashboardPlanDoesNotAllow";
public string Support { get; set; } = "DashboardSupport";
public string SupportDefaultContent { get; set; } = "_DashboardSupportDefaultContent";
public string SupportOptionalContent { get; set; } = "_DashboardSupportOptionalContent";
public string SupportContactusForm { get; set; } = "_DashboardSupportContactUsForm";
public string SupportOurAddress { get; set; } = "_DashboardSupportOurAddress";
public string ConsiderUpgradingPlan { get; set; } = "DashboardConsiderUpgradingPlan";
}
- As you can see it has quite a number of properties. But we are interested in the ones that starts with our action name Index
public class DashboardViews
{
public string Index { get; set; } = "DashboardIndex";
public string IndexDefaultContent { get; set; } = "_DashboardIndexDefaultContent";
public string IndexOptionalContent { get; set; } = "_DashboardIndexOptionalContent";
//...............
}
Index ( DashboardIndex.chtml) is the parent view which renders IndexDefaultContent (_DashboardIndexDefaultContent.cshtml) inside of it and gives you the default view.
Ignore _DashboardIndexOptionalContent for now.
Now lets create a view _DashboardIndexDefaultContent.cshtml in our app's views\shared folder
And we get this now
This is the easiest way for finding the view name to replace a default view with your custom view file.
In the appsettings.json/appserttings.Development.json file there is a setting (in Settings) called PrintViewname. If you assign value 1 to that setting then Exico Shopify Framework will add a custom html attribute to every parent div of every views (razor cshtml) it renders. Below is the screen shot of the plan/subscription choosing step showing the subscription pricing table during installation process. It is rendering the default look for that step. But if you want to change the color, look and feel or even structure of that orange pricing table using x-viewname then you have to go to html source of that page.Once you are in the html source you will see x-viewname attributes for different divs. It will also give you an idea about two things
- Where in the hierarchy that pricing div is (i.e. the immediate parent is shopifychooseplan.chtml** and the root parent is the _Layout.cshtml )
- What is the name of the view that you should use to create a new view in order to override the default one.
As you can see I am using developer tool on chrome and I can exactly pinpoint that orange div using inspect tool. And once I select it I can see that the view that is responsible for rendering the orange pricing div is called _ShopifyChoosePlanRenderer.cshtml. Now if I create a view named _ShopifyChoosePlanRenderer.cshtml in my views\shared directory then system will use your view instead of the default orange pricing table.
One interesting thing, if you are okay with the pricing table structure but only want to change the CSS(may be for changing font, color etc) then you can just override the _ShopifyChoosePlanRenderingCss.chtml (by creating a view using the same name in the views\shared folder).Have your custom CSS in there and the default pricing table will be rendered using your CSS rules.
There are some views that do not render directly as view. But they do some important tasks. For example what if you need to add few html meta fields or what if you need to include a css in the main layour so that it is loaded for ever page? To address these issues the framework has some special views. They are in fact razor files but instead of directly spitting out HTML they add html non-rendering elements into your views.
Let's go back to the ViewNames class once again
public class ViewNames
{
public const string SCRIPT_SECTION = "scripts";
public const string STYLE_SECTION = "styles";
public string ErrorPage = "XError";
//......skping few lines
public MetaViews Meta { get; set; } = new MetaViews();
//......skping remaining lines
}
Lets first talk about this ErrorPage (XError.cshtml) is used to render any error generated by the system.An instance of ErrorViewModel is passed to this view to render the error details.
public string ErrorPage = "XError";
Note that error details are shown based on IP addresses. If your IP address is listed as Privileged IP (see the Settings for more details) only then full details is revealed.
As for the
public const string SCRIPT_SECTION = "scripts";
public const string STYLE_SECTION = "styles";
They are the section names that you can use to render some CSS or JavaScript from any view. Section styles is rendered in the Header section of the page and the scripts section is rendered at the end of the body tag.
For example if you have a view_ myView.cshtml_ and you want to write some CSS for view but you want to put it inside the Header tag, then in your myView.cshtml file do the following
@section styles{
<style>
//your awesome css
</style>
}
Same goes for the JavaScript.If you write JavaScript anywhere in the _myView.cshtm _like below
@section scripts{
<script type='text/JavaScript'>
//your JavaScript code
</script>
}
then your JavaScript will be placed to the bottom of the body tag.
Now let's talk about the MetaView.
The content of the MetaView looks like this
public class MetaViews
{
public string DefaultMetaFields { get; set; } = "_DefaultMetaFields";
public string DefaultHeaderIncludes { get; set; } = "_DefaultHeaderIncludes";
public string DefaultAfterBodyIncludes { get; set; } = "_DefaultAfterBodyIncludes";
public string DefaultPageTitle { get; set; } = "_DefaultPageTitle";
public string CustomMetaFields { get; set; } = "_CustomMetaFields";
public string CustomHeaderIncludes { get; set; } = "_CustomHeaderIncludes";
public string CustomAfterBodyIncludes { get; set; } = "_CustomAfterBodyIncludes";
}
To understand the MetaViews class (in the ViewBagClasses.cs file) let's look at the default _layout.cshtml file
<head>
<!--The default implementation is "Title - App Name"-->
@await Html.PartialAsync(this.GetViews().Meta.DefaultPageTitle)
<!--Includes default meta fields.It also renders _CustomMetaFields if available-->
@await Html.PartialAsync(this.GetViews().Meta.DefaultMetaFields)
<!--Renders the default css files. Also renders _CustomHeaderIncludes internally if available-->
@await Html.PartialAsync(this.GetViews().Meta.DefaultHeaderIncludes)
....lines ommitted here for simplicity
</head>
Here are things that are happening
-
_DefaultPageTitle.cshtml file renders the <title>Page Title - App Name</title>. If you need to customize it then override it. That is create a _DefaultPageTitle.cshtml file in your views\shared folder.
-
_DefaultMetaFields.cshtml is adding default html meta field elements. If you need add add couple more then create a _CustomMetaFields.cshtml in your views\shared folder and add them there and it will be loaded inside the _DefaultMetaFields.cshtml after adding the default meta tags. You can also override _DefaultMetaFields.cshtml for complete control of what meta-tags are added in the rendered html pages.
-
_DefaultHeaderIncludes.cshtml includes default CSS , if you want to load your own then override _CustomHeaderIncludes.cshtml. Note that you can even add JavaScript here as well. But for that we recomment using _CustomAfterBodyIncludes.cshtml discussed later
-
All three above are rendered inside the header tag. Except the DefaultAfterBodyIncludes (that is the DefaultAfterBodyIncludes.cshtml). This one is rendered just before the end tag of the body.DefaultAfterBodyIncludes.cshtml mainly includes default JavaScript inside that view and after that it renders the _CustomAfterBodyIncludes.cshtml if available. So if you need to add few JavaScript files for your app then overriding the _CustomAfterBodyIncludes.cshtml (by creating it inside the views\shared directory) is the best way.
View all the view files source code Here, which is by the way best way to understand the view rendering work flow.
Very simple! Exico Shopify Framework uses bootstrap for everything. So adding a drop down menu is basically following bootstrap drop down code. However, real task here is to know what view to override! It is called _OptionalNavMenu.cshtml. Create a view file in your views\shared and paste this code snippet
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Test</a></li>
<li><a href="#">Test2</a></li>
<li class="divider"></li>
<li><a href="#">Test3</a></li>
<li><a href="#">Test4</a></li>
</ul>
</li>
How do I know the name of the view ? I first went to ViewNames class in the ViewBagClasses.cs file then looked for a property that has the word Nav in it. And I found this property
public NavBarViews NavBar { get; set; } = new NavBarViews();After that I went to the definition of the NavBarViews class in the same file and I then found the view name
public class NavBarViews { //....removed other properties for simplicity public string OptionalNavMenu { get; set; } = "_OptionalNavMenu"; }