I have a view that loads a set of modules (we will say other partial views) when the view renders.
So think of it like this in the master view:
<div>
@Html.PartialView("~/Views/MyApp/Partials/Module1.cshtml");
</div>
<div>
@Html.PartialView("~/Views/MyApp/Partials/Module2.cshtml");
</div>
<div>
@Html.PartialView("~/Views/MyApp/Partials/Module3.cshtml");
</div>
There is a model value that is altered in the partial view Module2.cshtml
. Actually it is altered in the action for the Module2
view. I am setting the model value in public ActionResult RenderChecklist(Model pageModel, IGrouping<string, ChecklistItem> list, int checklistCount)
:
if (itemCounter == itemCheckedCounter)
{
priorityCounter++;
pageModel.MyAppInfo.ChecklistPriorityLevel = priorityCounter;
listRestrict = "no-restrict";
overlayShow = "hidden";
}
else
{
listRestrict = "no-restrict";
overlayShow = "hidden";
}
Depending on the ChecklistPriorityLevel
value is determines if an overlay is shown in Module1
, Module3
, etc., but since Module1
loads before Module2
, the value of of ChecklistPriorityLevel
in Module1
is always initiated at 0.
The code in the partial view that is called in each module is something like this:
@if (moduleRestrict && !(moduleRestrictPriorityLevel <= checklistPriority) && !Model.GetValue<bool>("moduleRestrictBypass"))
{
const string moduleLockMessage = "This section is locked.";
<div class="module overlay show">
<img src="/assets/myapp/images/lock.png" alt="Module Lock">
<p>@moduleLockMessage</p>
</div>
}
The relative code in the model is just a regular get, set at this moment:
namespace MyApp.Core.MySite.Models
{
/// <summary>
/// Model for MySite.
/// </summary>
public class MyAppInfoModel
{
... //other models
[Ignore]
public int ChecklistPriorityLevel { get; set; }
}
}
So my question is how do I get the change in the value of this model to trigger the change in other modules (partial views) that have already loaded?
DISCLAIMER: I changed some of my actual code for privacy purposes. I am just trying to give enough information to have viewers understand what I am trying to do. I am looking for the best option, whether it is asynchronous, or whatever, to properly get the value in other partial views regardless of which partials load first.
Fix for my own issue (But I would still really like to see how this could be handled)
So for my particular problem I decided that I would just force the value of the model to be set before loading any of the modules. The way my app works, Module2 could be in any spot actually, and any modules could be ahead or behind Module2. What order the modules are in is determined in the backoffice. So I just decided to create a SurfaceController and get the data (checklists) on the main view, but then I have to get the data again in "Module2", which is my ChecklistModule. I don't really like having to iterate the checklists twice, but in order to get that ChecklistPriorityLevel
value I have to iterate through the checklists.
So in my main view a call the following:
MyAppChecklistController.SetChecklistPriorityLevel(Model);
Then my method is:
public static void SetChecklistPriorityLevel(MyAppRenderModel pageModel)
{
var checklist = GetCheckList(pageModel);
var priorityCounter = 1;
foreach (var list in checklist)
{
var listCount = list.Count();
var itemData = new ValueTuple<int, int, string>(1, 1, null);
itemData = list.OrderBy(x => x.IsChecked).ThenBy(x => x.SortOrder).Aggregate(itemData,
(current, item) => GetItemList(item, current.Item1, current.Item2, current.Item3, listCount));
var itemCounter = itemData.Item1;
var itemCheckedCounter = itemData.Item2;
// var itemList = itemData.Item3;
priorityCounter = GetPriorityLevel(itemCounter, itemCheckedCounter, priorityCounter);
pageModel.ChecklistPriorityLevel = priorityCounter;
}
}
Then when I render the checklist in the ChecklistModule partial view:
[ChildActionOnly]
public ActionResult RenderChecklist(IGrouping<string, ChecklistItem> list,
int checklistCount, int checklistCounter, int priorityCounter)
{
var parentFolder = list.First().UmbracoContent.Parent;
var listCount = list.Count();
var itemData = new ValueTuple<int, int, string>(1, 1, null);
var color = GetChecklistColorValue(parentFolder);
itemData = list.OrderBy(x => x.IsChecked).ThenBy(x => x.SortOrder).Aggregate(itemData,
(current, item) => GetItemList(item, current.Item1, current.Item2, current.Item3, listCount));
var itemCounter = itemData.Item1;
var itemCheckedCounter = itemData.Item2;
var itemList = itemData.Item3;
var checklistDict = GetChecklistRestrictions(parentFolder, itemCounter,
itemCheckedCounter, priorityCounter);
checklistDict.Add("color", color);
checklistDict.Add("itemList", itemList);
checklistDict.Add("checklistCounter", checklistCounter);
return GetChecklistLayout(checklistCount, checklistLayoutDict);
}
So as you can see I am pretty much running through the checklist twice in one page load. I didn't want to have to do that. If anyone has a better idea to make this more efficient, let me know.
UPDATE: The above solution (even though only part of the code is posted) fixed my issue, however I decided that I would just catch the checklist on the view and add it to the models too, then use that model (pageModel.Checklists) in the partial, so I am not actually grabbing the checklist twice with Linq. I still have to iterate through the checklists twice, but I am not grabbing the values twice. So still more of a hack, but maybe I will keep finding a way later to streamline this.