I have code only component, where I generate my menu, where I got around 700 records where all of them are loaded at once. I decided to recreate it and load another menu objects to menu on click event.
Here is my viewmodel for my menu, I removed some not related parts from my viewmodel
public class CategoryMenuViewModel : DotvvmViewModelBase
{
public static CategoryMenuFacade MenuFacade { get; private set; }
public static List<CategoryMenuDTO> CategoryMenuList { get; set; } = new List<CategoryMenuDTO>();
//private static bool LoadMoreCategories { get; set; }
public CategoryMenuViewModel(CategoryMenuFacade categoryMenuFacade)
{
MenuFacade = categoryMenuFacade;
}
public override Task PreRender()
{
if (!Context.IsPostBack)
{
CategoryMenuList.AddRange(CategoryMenuFacade.GetCategoryMenu(CategoryId));
//CategoryMenuList = MenuFacade.GetCategoryMenu();
}
return base.PreRender();
}
public static int? CategoryId { get; set; }
public static List<int> PreviousCategoryId { get; set; } = new List<int>();
[AllowStaticCommand]
public static List<CategoryMenuDTO> SelectedCategory()
{
if (CategoryId == null) return CategoryMenuList;
bool idExist = PreviousCategoryId.Any(r => r == CategoryId);
if (!idExist)
{
PreviousCategoryId.Add((int)CategoryId);
CategoryMenuList.AddRange(MenuFacade.GetCategoryMenu(CategoryId));
}
return CategoryMenuList;
}
}
My previous thought was that I can load another parts of menu using this script where I get object Id on which I clicked and send it to viewmodel. It works fine, but problem with this approach is, that it fires PreRender()
method and loads all data again from another viewmodels.
dotvvm.events.beforePostback.subscribe(function (data) {
try {
var selectedCategory = $(event.target.lastChild);
var nodeId = selectedCategory[0].attributes.Id.nodeValue;
var idNumber = nodeId.substring(nodeId.indexOf("_") + 1);
data.viewModel.CategoryMenuViewModel().CategoryId = idNumber;
} catch (error) {
// continue with error
}});
My other thought was about using knockout binding handler
where I am able to update my CategoryId
property in viewModel, but I dont know exactly, how I can fire my some method in viewModel or even code-only-component
to render new data.
ko.bindingHandlers["click"] = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
$(element)
.on('click', function (e) {
var selectedCategory = $(e.target.lastChild);
var nodeId = selectedCategory[0].attributes.Id.nodeValue;
var idNumber = parseInt(nodeId.substring(nodeId.indexOf("_") + 1));
//data.viewModel.CategoryMenuViewModel().CategoryId = idNumber;
// if someone deletes the value from the textbox, set null to the viewmodel property
var prop = valueAccessor();
if (ko.isObservable(prop.CategoryItemId)) {
prop.CategoryId(idNumber);
}
});
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
// get the value from the viewmodel
var value = ko.unwrap(valueAccessor());
var test = viewModel.CategoryId();
}};
Here is my view
<cc:CategoryMenu DataContext="{{value: CategoryMenuViewModel}}" class="categorieMenu" ID="mainMenu"/>
And .dotcontrol
file
<coc:CategoryMenu DataSource="{{value: CategoryMenuViewModel.CategoryMenuList}}"
ActiveCategory="{{controlProperty: ActiveCategory}}"
SelectedValue="{{value: CategoryMenuViewModel.CategoryId}}"
ItemValueBinding="{{value:Id}}"
data-bind="click: {CategoryId}"
Click="{{staticCommand: CategoryMenuViewModel.SelectedCategory()}}"/>
Short preview of properties in my coc
public static readonly DotvvmProperty ChangedProperty
= DotvvmProperty.Register<Command, CategoryMenu>(c => c.Changed, null);
public Command Changed
{
get => GetValue(ChangedProperty) as Command;
set => SetValue(ChangedProperty, value);
}
public int SelectedItemId
{
get => (int)GetValue(SelectedItemIdProperty);
set => SetValue(SelectedItemIdProperty, value);
}
public static readonly DotvvmProperty SelectedItemIdProperty
= DotvvmProperty.Register<int, CategoryMenu>(c => c.SelectedItemId);
So my question is, how I can handle changed event to fire method which will load another parts of my menu and render it using my component?