Search code examples
asp.net-mvc-4knockout.jsknockout-mvc

KnockoutMVC Foreach Lambda filter (or any filter)


I have been able to create a display that loops a list of pages. This will display all pages in the DB table like the following.

@using (var page = ko.Foreach(m => m.PageList))
{
    @page.Html.TextBox(p => p.PageErrorMessage)
    @page.Html.TextBox(p => p.PageSuccessMessage)
    @page.Html.TextBox(p => p.Title)
    @page.Html.TextBox(p => p.Content)
}

I am would like to be able to filter what displays by a lambda expression on the Foreach. Currently that returns the type IEnumerable, even with a ToList() at the end the following does not work.

//Note: I have tried .Where pl.Title == "string" with the same results
@using (var page = ko.Foreach(m => m.PageList.Where(pl => pl.Title.Contains("Page01")))
{
    @page.Html.TextBox(p => p.PageErrorMessage)
    @page.Html.TextBox(p => p.PageSuccessMessage)
    @page.Html.TextBox(p => p.Title)
    @page.Html.TextBox(p => p.Content)
}

I can get the results that I want, but it seems cumbersome to do this. If I add a visible check to each field with the same check I only see the fields I want.

//Note: p.Title.Contains("string") does not work for me in the Visible here
@using (var page = ko.Foreach(m => m.PageList))
{
    @page.Html.TextBox(p => p.PageErrorMessage).Visible(p => p.Title == "Page01!")
    @page.Html.TextBox(p => p.PageSuccessMessage).Visible(p => p.Title == "Page01!")
    @page.Html.TextBox(p => p.Title).Visible(p => p.Title == "Page01!")
    @page.Html.TextBox(p => p.Content).Visible(p => p.Title == "Page01!")
}

Is there a better way to work with foreach to filter down the list or is this currently designed to always return the full set?


Solution

  • You cannot use C# code in razor to modify your viewmodel. To bind against something it needs a representation in the viewmodel. If you want to filter the full list, a computed property on the viewmodel should do the trick.

    [Computed]
    public List<Page> FilteredList
    {
      get { return PageList.Where(pl => pl.Title.Contains("Page01")); }
    }