DotVVM 2.0.0-beta01
Pre-releaseBinding Properties
see Binding System Refactoring #341
- Better Javascript translator
- In the ViewModelSerializationMap it's possible to rename properties for client-side and JavascriptTranslator will translate it correctly, use
Bind(Name = "MyName")
attribute - Null checks in binding were previously done by
try ... catch
, which also caught exception inside called functions. Now it is done by real checks, so inner exceptions are propagated correctly - Binding can be transferred from one control to another in different data context and they will still evaluate and translate to JS correctly
- This means that you can use inherited properties to transfer dependencies into your markup control even though they are deeply nested
- You can even use MarkupControls recursively, just make sure they are server-rendered
- Super cool extensibility
- Extension parameters like
_collection
,_index
and_api
are just a tip of the icebergs ;)
- Extension parameters like
- Bindings have ResultType property accessible at runtime
- Controls have DataContextType property accessible at runtime
- Command Binding IDs are "more" unique and less readable
Function Arguments in Bindings
All bindings now have an implicit conversion to a delegate - essentialy, when the expected type is a delegate, the binding is wrapped in lambda. In Javascript it's represented as a function. And when the delegate contains any parameters, these get registered as additional symbols to the parser. For example to set (a) => a + 1
into a property of type Func<int, int>
you can use {value: arg + 1}
To use the parameters with staticCommand you can set the commandArgs symbolic parameter (the same way you'd do with command binding)
REST API
DotVVM allows interacting with REST APIs directly from the DOTHTML views. You can fill GridView, Repeater and other controls with data from the REST API, and use Button or other controls to call REST API methods as a response to user action. It is also possible to refresh data that have already been loaded (in the GridView for example) based on a change of a particular viewmodel property, or explicitly.
See: https://www.dotvvm.com/docs/tutorials/basics-rest-api-bindings/2.0
Model state helpers
You can just viewModel.AddModelError(v => v.MyObject.PartOfTheForm.Property3, "It's invalid")
instead of creating JS evaluatable string path
Controls improvements
- ComboBox.ItemValueBinding and ItemTextBinding - use them instead of ValueMember and DisplayMember
- TextBox.ValueType is obsolete, it's infered from result type of
Text
property
string.Format in value bindings
string.Format
method is correctly translated to Javascript. You can also use [primitive type].ToString("Format")
method - this one is also two-way, so it's possible to use it instead of FormatString
property on TextBox.
Route Groups
see #363
you can register routes in groups with specified path and id prefixed to prevent repetitive literals and help with visual code orientation:
routes.AddGroup(name: "Admin", prefix: "admin", virtualPath: "Views/Administration", content: adminRoutes =>
{
// adminRoutes is of type RouteTable
adminRoutes.Add("Users", "users", "Users.dothtml"); // name = Admin_Users, path = "admin/users", virtualPath = "Views/Administration/Users.dothtml"
adminRoutes.Add("Articles", "articles", "Articles.dothtml");
});
Dependency Injection into controls
It works in two modes:
- Simple/intuitive/automatic/hipster mode - when the control does not have a parameterless constructor, it is initialized from the default IServiceProvider. It is used mainly for infrastructure controls that need to get some dotvvm service, for non-control DotvvmBindableObjects that need or on Asp.NET Core projects that use the default DependencyInjection properly.
- Explicit/enterprise mode - when the control is marked by [RequireDependencyInjection] it is created using resolver registered in the default IServiceProvider. You can use it if you want services from your separate container or need some weird injection features, like property injection
Dependency Injection into dothtml views
You can require a service using @service
directive. It is mainly useful for Asp.Net Core ILocalizer interface and for calling static commands. The service usage can't be translated to Javascript, so usage in value binding will throw an exception.
@service myService = IMyService<string>
{{resource: myService.SomeProperty}}
{{command: myService.DoSomething()}}
Markup controls packed into dlls
Markup file loaded supports embedded://...assembly name/...name of the resource
syntax for referencing embedded resources from view or markup control registration. It should allow you to pack dotcontrol
files into the dll and distrube them in a library. The files are referenced as the original source code and have to be compiled in the target project, so you can apply compile-time styles to them.
IncludeInPage
property
Just a wrapper for knockout if
binding handler.
FormControls.Enabled
property
Added a FormControls.Enabled attached property which disables controls inside that are not explicitly enabled.
Controls affected
- in DotVVM - Button (ButtonBase), CheckBox (CheckableControlBase), ComboBox (SelectorBase), DataPager, LinkButton (ButtonBase), ListBox (SelectorBase), RadioButton (CheckableControlBase), TextBox
- in Bootstrap - Button, CheckBox, DataPager, RadioButton, TextBoxGroup
- in Business pack - Button, Calendar, CheckBox, CheckBoxList, ColorPicker, ComboBox, DataPager, DateTimePicker, DateTimeRangerPicker, DropDownList, MultiSelect, NumericUpDown, RadioButton, RadioButtonList, RangeCalendar, RangeSlider, Rating, Slider, TextBox
Example
<div FormControls.Enabled="{value: false}">
<dot:Button Text="I am disabled" />
<dot:Button Text="I am enabled" Enabled="{value: true}" />
</div>
dot:BodyResourceLinks
and dot:HeadResourceLinks
When you use one of these controls in page, the resources will be render in location that is defined by the control. Only the first control on the page is activated to prevent accidential multiple times included scripts.
LocalizablePresenter
It's a utility for easy localization based on query string or route parameters. It just sets the Thread
s
current culture.
// based on query string parameter lang, `myPage?lang=cs-CZ` will be in czech culture
config.RouteTable.Add("myRoute", "myPage", "myPage.dothtml", presenterFactory: LocalizablePresenter.BasedOnQuery("lang"));
// based on parameter lang, `cs-CZ/myPage` will be in czech culture
config.RouteTable.Add("myRoute", "{lang}/myPage", "myPage.dothtml", presenterFactory: LocalizablePresenter.BasedOnParameter("lang"));
By default, it redirects to a default culture when a invalid code is specified, you can disable that using redirectWhenNotFound
parameter.
see #513
Custom constuctor for serializer
On a IViewModelSerializationMapper
, you can set your own method to create a new instance of the viewmodel.
mapper.Map(m => {
// create from Asp.Net DI
m.AllowDependencyInjection();
// custom constructor
m.SetConstructor(serviceProvider => SomehowCreateViewModel(serviceProvider))l
});
Ben.Demystify for the error page
By default, the error page uses Ben.Demystify
library to show nicer stack traces.
Implemented CSS style bindable
Added Style-*
property group that generates the style
knockout binding. I'm not sure what type should I use for the property group, currently there is object
.
Usage example:
<div Style-color="{value: Color}" Style-display="{value: Condition ? 'none' : 'inline-block'}"/>
<div style="background-color: green;" Style-width="{value: Width + 'px'}"/>
see #572