I'm trying to pass page as argument in Umbraco . and in a helper I need some properties of the page . like Name , ...
This is my code :
var PageWeAreInheritedFrom = CurrentPage;
#ShowBanner(PageWeAreInheritedFrom);
#helper ShowBanner(dynamic pageWeRIn)
{
if (pageWeRIn.bannerIsInherited)
{
#ShowBanner(pageWeRIn.Parent)
}
else
{
//here I want to have a switch case based on pageWeRIn.Name
//but I cant have it.
}
}
This is the Error .seems the page type is different in the helper method
A switch expression or case label must be a bool, char, string,
integral, enum, or corresponding nullable type
This is caused because pageWeRIn is dynamic and C#'s switch can't work with dynamic variables. I personally don't work with dynamics in my views but only with typed models. For more information see: http://24days.in/umbraco-cms/2015/strongly-typed-vs-dynamic-content-access/
A typed implementation would look somehthing like this (not tested):
#ShowBanner(Mode.Content);
#helper ShowBanner(IPublishedContent pageWeRIn)
{
if (pageWeRIn.GetPropertyValue<bool>("bannerIsInherited"))
{
#ShowBanner(pageWeRIn.Parent)
}
else
{
//use all the switches you want on pageWeRIn.Name
}
}
Another way to do it without changing the whole code would be to introduce a new variable that's typed (as Jannik explained in his comment) and then use a switch
string nodeName = pageWeRIn.Name
switch(nodeName){
// whatever
}
Related
I have in the .ts file the following code:
set query(query: string) {
this.form.get('query').setValue(query);
}
get query() {
return this.form.controls.query;
}
I am trying to call the getter method in .html file as:
<div *ngIf="!query.valid && (query?.dirty || query?.touched)">
<div [hidden]="!query.errors.required">Query is required</div>
</div>
However, an error is thrown. The code works perfectly if I remove the setter from the .ts file.
Why does this happen?
You can do it via two ways,
Way 1:
set query(query: any) {
this.form.get('query').setValue(query);
}
get query() {
return this.form.controls.query;
}
Way 2:
set query(query: string) {
this.form.get('query').setValue(query);
}
get query(): AbstractControl {
return this.form.controls.query;
}
when you assign a value to query you are assigning it as a string see the incoming argument type in your setter. So by default angular understands it as string type. Then in your HTML, you try to access it as an object which creates a problem for angular as it expects it to be a string but used as an object.
try form.getControls['query'].setValue(myValue)
form.get('fieldName') will get value of that field ...
form.controls['fieldName'] would get the field itself .. Field control will expose get or set value methods
Although the accepted answer works and the thinking behind it make sense, I would completely avoid using any as a return type, when you know exactly what you're returning.
That just goes against the purpose of using Typescript as a language. Using any is the same as saying "accept everything and don't just interpret it as a string".
set query(query: string) {
this.form.get('query').setValue(query);
}
get query(): AbstractControl {
return this.form.controls.query;
}
Since you know you're returning an AbstractControl, I would set the return type to either AbstractControl or, if you want to be more specific, to FormControl.
I want to check that if a member function of a particular name exists on a object, if it does call the member function or make a reference of that member function.
Here I don't have type of the object, i.e. the object maybe does not implement any interface but has a member function cancel().
I used this method (reflection) to check if the member function exists, i.e. if (object::class.members.any { it.name == "cancel" }) and when this statement returns true I am sure that the method does exist but compiler is still unsure that the 'cancel' method exist in the object or not
fun canceller(object: Any): KFunction<Any>?
{
var canceller: KFunction<Any>? = null
// check if object has member function 'cancel'
if (object::class.members.any { it.name == "cancel" })
{
// make reference of that member function and return it
canceller = object::cancel //cancel is still not recognized as a member function and gives an error that "Unresolved reference: cancel"
// or just call it now
// object.cancel()
}
return canceller
}
I expect that canceller variable should be assigned to value.cancel(), but the compiler is unsure that cancel() function exist (with an error "Unresolved reference: cancel") in the object even after we supplied a check inside if statement
It's not meant to be used like this. Reflection is something you use if you don't know at compile time what you are dealing with at runtime. Some examples:
you need to use a type that's configured in some properties file (Class.forName("someTypeString").newInstance())
you have written an utility that extracts the contents of your object for debugging purposes
you need to access code that isn't really visible to you (private fields that you can't easily access, but you need to)
many more... but most of the time very special use-cases
Now what you have shown is a function reference (object::cancel). In order to use a function reference the compiler must know the type of object and the cancel-function must exist for that type. As object is of type Any and the if-condition is only relevant at runtime, the compiler does not know that there is a cancel-function available and therefore compilation fails.
Note that if you aren't doing anything special, you should rather check for a common type/interface. So for example, if your objects implement an interface Cancellable you could just change your code to something as follows:
fun canceller(object: Any): KFunction<Any>? {
var canceller: KFunction<Any>? = null
// check if object is of type Cancellable
if (object is Cancellable) {
// make reference of the Cancellable::cancel-function
canceller = object::cancel // smart-cast acting
// or you could also call it directly: object.cancel()
}
return canceller
}
or probably you could just spare that function altogether and end up with something like just:
val someObj : Cancellable = ...
// somewhere later:
someObj.cancel()
Reflection is rather expensive and if you aren't entirely sure what it is useful for, you should not use it.
If you really knew what you were doing... then ok... it's of course also possible to call that function via reflection and if you ask for the existance of a function via reflection you also have to call it via reflection:
object::class.members.first {
// note: I am using just the first function... if there are several, you need to check which one to use (parameter/type)
it.name == "cancel"
}
.call(object)
I think you can use reflections for this purpose.
myObject.javaClass.kotlin.members.any { it.name == "cancel" }
And the better way to express the idea of "object that has all the variables" is to define the interface and have all those object implemented
interface Achiever { val name: String }
I'm using babel6 and for my pet project I'm creating a wrapper for XMLHttpRequest, for the methods I can use:
open = (method, url, something) => {
return this.xhr.open(method, url, something);
}
but for the properties arrow function doesn't work
this works:
get status() { return this.xhr.status; }
but I can not use
get status = () => this.xhr.status;
Is this intentional?
According to the ES2015 grammar, a property on an object literal can only be one of three things:
PropertyDefinition:
IdentifierReference
PropertyName : AssignmentExpression
MethodDefinition
The only one of these type that allows a leading get is MethodDefinition:
MethodDefinition :
PropertyName ( StrictFormalParameters ) { FunctionBody }
GeneratorMethod
get PropertyName ( ) { FunctionBody }
set PropertyName ( PropertySetParameterList ) { FunctionBody }
As you can see, the get form follows a very limited grammar that must be of the form
get NAME () { BODY }
The grammar does not allow functions of the form get NAME = ....
The accepted answer is great. It's the best if you're willing to use normal function syntax instead of compact "arrow function syntax".
But maybe you really like arrow functions; maybe you use the arrow function for another reason which a normal function syntax cannot replace; you may need a different solution.
For example, I notice OP uses this, you may want to bind this lexically; aka "non-binding of this"), and arrow functions are good for that lexical binding.
You can still use an arrow function with a getter via the Object.defineProperty technique.
{
...
Object.defineProperty(your_obj, 'status', {
get : () => this.xhr.status
});
...
}
See mentions of object initialization technique (aka get NAME() {...}) vs the defineProperty technique (aka get : ()=>{}). There is at least one significant difference, using defineProperty requires the variables already exists:
Defining a getter on existing objects
i.e. with Object.defineProperty you must ensure that your_obj (in my example) exists and is saved into a variable (whereas with a object-initialization you could return an object-literal in your object initialization: {..., get(){ }, ... }). More info on Object.defineProperty specifically, here
Object.defineProperty(...) seems to have comparable browser support to the get NAME(){...} syntax; modern browsers, IE 9.
I'm using the fluent syntax and lambdas for data binding in MvvmCross. An example of this is:
var bindings = this.CreateBindingSet<MyTableCell, MyTableCellViewModel>();
bindings.Bind(titleLabel).To(vm => vm.MY_TITLE);
bindings.Apply();
Whenever I try this with an underscore in a view model property I get an exception:
Cirrious.CrossCore.Exceptions.MvxException: Unexpected character _ at
position 3 in targetProperty text MY_TITLE
I believe the error message is a result of MvvmCross parsing the data binding, yet this seems to only make sense for people using string-based data binding, not the lambda expression syntax.
Unfortunately, I cannot change the view models so I'm looking for a workaround to allow underscores in the view models. Any ideas?
I'd guess this is a general problem in the MvvmCross parser - probably in
private void ParsePropertyName()
{
var propertyText = new StringBuilder();
while (!IsComplete && char.IsLetterOrDigit(CurrentChar))
{
propertyText.Append(CurrentChar);
MoveNext();
}
var text = propertyText.ToString();
CurrentTokens.Add(new MvxPropertyNamePropertyToken(text));
}
In https://github.com/MvvmCross/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Binding/Parse/PropertyPath/MvxSourcePropertyPathParser.cs#L80
Which probably needs to be fixed to something like:
while (!IsComplete &&
(char.IsLetterOrDigit(CurrentChar) || CurrentChar == '_')
There are workarounds you could do, but the easiest solution is probably to fix this and rebuild, rather than to try workarounds.
But if you do want to try workarounds....
Assuming this is static (non-changing) text and this is just a one-off for now, then one workaround might be to add a property to your cell called Hack and to then bind like:
bindings.Bind(this).For(v => v.Hack).To(vm => vm);
//...
private MyTableCellViewModel _hack;
public MyTableCellViewModel Hack
{
get { return _hack; }
set { _hack = value; if (_hack != null) titleLabel.Text = _hack.MY_VALUE; }
}
Another alternative (with the same assumptions) might be to use a value converter -
bindings.Bind(titleLabel).To(vm => vm.MY_TITLE).WithConversion(new WorkaroundConverter(), null);
// ...
public class WorkaroundConverter : MvxValueConverter<MyTableCellViewModel, string>
{
protected override string Convert(MyTableCellViewModel vm, /*...*/)
{
if (vm == null) return null;
return vm.MY_TITLE;
}
}
Using a value converter in WPF, you can return something like DependecyProperty.UnsetValue or Binding.DoNothing as special values to say leave the binding alone. Is there a similar mechanism in MVVMCross?
To be more specific about what I'm trying to do, is I have a view model property that is a three-state enum that I need to bind to 3 binary controls. So I thought I could bind each of the controls to a MyEnum -> bool converter that will have a conversion parameter set to the value of the converter and in the Convert method it will return true if the MyEnum state is equal to the parameter and false otherwise. So far so good. But I want this binding to be two-way, so I need to convert back. My convert back works something like this:
protected override MyEnum ConvertBack(bool value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter is MyEnum)
{
if (value)
{
return (MyEnum)parameter; // this is fine
}
else
{
return ???
}
}
return base.ConvertBack(value, targetType, parameter, culture);
}
Basically, what I want to be able to do is say, if the state of my control is true update the bound property on my view model to be the same as the parameter, if not, leave the view model property alone.
Maybe this is the problem with using the strongly typed value converters?
If anybody else encounters a similar problem, in addition to Stuart's suggestions, this is what I actually ended up doing.
In the View Model
private MyEnum _selectedValue = MyEnum.SomeValue;
public MyEnum ? SelectedValue
{
get
{
return _selectedTab;
}
set
{
if (value.HasValue)
{
_selectedTab = value.Value;
RaisePropertyChanged(() => SelectedTab);
}
}
}
Then in my converter (now a MvxValueConverter<MyEnum?, bool>):
protected override MyEnum? ConvertBack(bool value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter is MyEnum) // this is just a sanity check
{
if (value)
{
return (MyEnum)parameter;
}
else
{
return null
}
}
return base.ConvertBack(value, targetType, parameter, culture);
}
It's not a general solution, but it fits my immediate need.
Update: UnsetValue is now available in mvvmcross - so this answer is no longer required.
Binding.DoNothing, DependencyProperty.UnsetValue or equivalent are currently not implemented in the MvvmCross binding system, and I don't believe there are any feature or pull requests currently open on this.
I'm afraid I don't really understand your example - the 'conversion parameter set to the value of the converter' and the if (parameter is MyEnum) snippet rather threw me - as far as I know, the parameter in windows xaml binding is a constant so I don't quite understand this example. Sorry if I've misunderstood.
Regardless, some possible approaches that might be used to assist with getting this functionality up and running in your mvx app are:
You could throw an exception from the ValueConverter:
For the Convert direction, the binding FallbackValue is used if a ValueConverter fails (throws an exception)
For the ConvertBack direction, the binding does nothing if an exception is thrown (although this would unfortunately generate some trace "error" output each time)
You could implement a custom binding for your control - something which only fires change updates when the change is one you are interested in (some custom bindings are introduced in N=28 in http://mvvmcross.wordpress.com which creates bindings like BinaryEditFooTargetBinding.cs - it would be straight-forward to customise/filter the TargetOnMyCountChanged behaviour in that class)
You could implement a custom binary control - which only fires change updates when the change is one you are interested in (for various platforms, some custom controls are introduced in N=18 to N=20 in http://mvvmcross.wordpress.com)
You could implement ViewModel binary properties which mirror your View and map to your three state enum
You could use a ValueCombiner within the Tibet binding system - it should be relatively straight-forward to work out a combiner based on top of something like MvxSingleValueCombiner.cs
Alternatively/additionally, please do also consider raising a Feature and/or Pull Request for this 'do nothing' type of functionality to be included in the TryGetValue/SetValue methods in https://github.com/slodge/MvvmCross/blob/v3/Cirrious/Cirrious.MvvmCross.Binding/Bindings/SourceSteps/MvxSourceStep.cs#L66 - but obviously the timeline on that might be longer.