This may be documented somewhere, but I cannot find it.
I am using the Sitecore helper and razor syntax to place values into my view:
#Html.Sitecore().Field("foo");
This works fine, but, I have Fields defined in Groups, and a few of them have the same name, like:
Group1: foo
Group2: foo
Question: Is there any way to access the field by group?
Something like this (what I have already tried):
#Html.Sitecore().Field("Group1.foo");
As long as I know it is not possible to use the sections name.
I would avoid to have the same field name even between differents sections.
Or a option is to pass the field ID and then create classes or constants to not hard code IDs
#Html.Sitecore().Field("{E77E229A-2A34-4F03-9A3E-A8636076CBDB}");
or
#Html.Sitecore().Field(MyTemplate.MyGroup.Foo); //where foo returns the id.
EDIT:
MyTemplate.MyGroup.Foo would be classes/structs you created your own just to make easier and more reliable the references all over you project. (you can use a tool to auto-generate it like a T4 template)
public static struct MyTemplate
{
public static struct MyGroup1
{
public static readonly ID Foo = new ID("{1111111-1111-1231-1231-12312323132}");
}
public static struct MyGroup2
{
public static readonly ID Foo = new ID("{9999999-9999-xxxx-1231-12312323132}");
}
}
Try accessing via the GUID of the field. This way, even if they have the same name, the API will be able to load the appropriate field.
Related
I'd like to create a GUI table to display a given list of features of an EObject sub-class. To do this I have to get the display names of the features for the column header.
How do I get the feature display names in the best way?
One solution that seems a bit like a hack:
If I have an instance of the class then I can use the adaptor factory to get a IItemPropertySource that can do this:
SomeEntity e = ...
String displayName = adaptorFactory.adapt(e, IItemPropertySource.class)
.getPropertyDescriptor(null, feature).getDisplayName(null));
But when the table is empty there is no SomeEntity object handy to use to get the IItemPropertySource.
I can create a dummy object using the EFactory in this way:
EClass containingClass = feature.getEContainingClass();
SomeEntity dummy = containingClass.getEPackage().getEFactoryInstance()
.create(containingClass));
... and then use that object the get the IItemPropertySource. But this seem a bit like a hack. Is there no better solution?
If you know the class at compile time, you can create the ItemProviderAdapter yourself:
MyClassItemProvider provider = new MyClassItemProvider(adaptorFactory);
String name = provider.getPropertyDescriptor(null, property).getDisplayName(null);
If you do not know the class at compile time, but only have an EClass instance at runtime, things are more complicated, because the necessary methods are protected. You have to "make" them public first.
I would add respective methods to the generated MyPackageSwitch and MyPackageAdapterFactory classes (in myPackage.util).
In MyPackageAdapterFactory:
/**
* #generated NOT
*/
public MyPackageSwitch<Adapter> getModelSwitch() {
return modelSwitch;
}
In MyPackageSwitch:
/**
* generated NOT
*/
public T doPublicSwitch(EClass theEClass, EObject theEObject) {
return doSwitch(theEClass, theEObject);
}
Now you can create an ItemProviderAdapter for an EClass theEClass like this:
provider = (ItemProviderAdapter) adapterFactory.getModelSwitch()
.doPublicSwitch(theEClass, null);
EMF was obviously not made for this. Keep in mind that this all is only working if you do not have any custom provider implementations that uses the EObject values.
Most examples I can find describe very simple/basic things, such as showing attributes of a person object like this:
The name is {{.Name}}. The age is {{.Age}}.
What happens if you have a more complicated web page, for example, multiple different objects and lists of objects, i.e. How do you do something like this:
{{p.Name}} is aged {{p.Age}}.
Outstanding invoices {{invoices.Count}}
<table>
<tr><td>{{invoices[0].number}}</td></tr>
.... etc...
You can declare and pass in an anonymous struct like this:
templ.Execute(file, struct {
Age int
Name string
}{42, "Dolphin"})
and access the variables like:
{{.Age}}, {{.Name}}
While this still requires you to make a struct, it is among the most concise ways to do it. You'll have to decide if it is too ugly for you ;)
You can put your more complex data into struct, and pass it just like you did Name and Age. For example,
type vars struct {
P User
Invoices []Invoice
}
type User struct {
Name string
Age int
}
type Invoice {
Number int
Description string
}
If you pass an instance of vars into the template execution, you can reference sub-structures by using dots and array indexes, just like in regular go code.
{{.P.Name}}, {{.P.Age}}, {{.Invoices[0].Number}}
It depends on what your data is.
I want to categorise this.
Primary data that the template is meant for. In your example that would be Invoice/Invoicelist. If you have to pass more than one of these you have to reconsider your template design.
Secondary data such as logged in user information or any common information that you find yourself passing into several templates.
Since these information are common. I usually make them into functions. Since these functions cannot have input params. You might want to create them as closures (within another function). Assign these function to funMap and add it to the template after parsing.
func MakeFuncMap(u *user) map[string]interface{} {
return map[string]interface{}{
"User": func() *user {return u}, //Can be accessed by "User." within your template
}
}
t, err := template.New("tmpl").Funcs(MakeFuncMap(nil)).Parse("template") //You will need to append a dummy funcMap as you will not have access to User at the time of template parsing
//You will have to clone the template to make it thread safe to append funcMap.
tClone, _ := t.Clone()
tClone.Funcs(MakeFuncMap(u)).Execute(w, invoicelist)
Now you can execute the template with only the invoicelist as data.
Within your template you should be able to access user information using "User." and invoice list by "."
You should be able to define the funcMap once for all the common data. So that you will be able reuse it.
To loop through a invoicelist you can look into range
{{range .}} //if you are passing invoicelist then the . means invoicelist
//in here . means each of the invoice
<label>{{User.Name}}, {{User.Age}}</label>
<label>{{.Id}}</label>
{{end}}
EDIT: Included fix for issue pointed out by Ripounet
Is it somehow possible to add the sub-group of a cetrain group the address is assigned to the html output?
In the template I have ###MAINGROUP### and ###GROUPLIST###. I can't use maingroup, cause it's not the case that the group I need is always the maingroup. And with the grouplist I can't say which group is the sub-group of the one group.
Anyone have an idea how I could do it?
And in addition to that I also need the value of a self created field in the tt_address table.
Edit:
I try it like #lorenz say. What I have so far:
ext_localconf.php:
<?php
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_address']['extraItemMarkerHook'][]
='EXT:txnextaddresssort/class.tx_next_address_sort_addmarkers.php:tx_next_address_sort_addmarkers';
class.tx_next_address_sort_addmarkers.php:
<?php
class tx_next_address_sort_addmarkers {
function extraItemMarkerProcessor(&$markerArray, &$address, &$lConf,
&$pObj) {
$lcObj = t3lib_div::makeInstance('tslib_cObj');
$lcObj->data = $address;
$markerArray['###SORTBEREICH###'] =
$lcObj->stdWrap($address['tx_nextaddresssort_sort_bereich'],
$lConf['tx_nextaddresssort_sort_bereich.']);
}
}
Extentionkey: next_address_sort
All I get is a blank screen, but no errors in apache log
No, there is no possibility to do that.
Yet you can write a custom extension that integrates the extraItemMarkerProcessorhook in tt_address. In ext_localconf.php, add:
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['tt_address']['extraItemMarkerHook'][] ='EXT:myextension/class.tx_myextension_filename.php:tx_myextension_classname';
Then add a file class.tx_myextension_filename.php to your extension.:
class tx_myextension_classname {
public function extraItemMarkerProcessor(&$markerArray, &$address, &$lConf, &$pObj) {
$lcObj = t3lib_div::makeInstance('tslib_cObj');
$lcObj->data = $address;
$markerArray['###MYFIELD###'] = $lcObj->stdWrap($address['myfieldlikeindatabase'], $lConf['myfieldlikeindatabase.']);
return $markerArray;
}
}
This would be an example for getting a field that is in the tt_address table and adding it to the markers so they can be used in a template. It is also stdWrap enabled.
Now, instead of getting a field, you should replace $address['myfieldlikeindatabase'] with a variable that contains the information you need. To receive the data, you can use the TYPO3 database API functions ($GLOBALS['TYPO3_DB']).
I am trying to learn MVC4 and i've come to this chapter called validation.
I came to know about DataAnnotations and they have pretty neat attributes to do some server side validation. In book they have only explained about [Required] and [Datatype] attribute. However in asp.net website i saw something called ScaffoldColumn and RegularExpression.
Can someone explain what they are, even though I know little what RegularExpression does.
Also are there any other important validation attributes I should know?
Scaffold Column dictates if when adding a view based on that datamodel it should/not scaffold the column. So forexample your model's id field is a good candidate for you to specify ScaffoldColumn(false), and other foreign key fields etc.
I you specify a regular expression, then if you scaffold a new view for that model,edit customer for example, a regex or regular expression on field will enforce that entered data must match that format.
You can read about ScaffoldColumnAttribute Class here
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
}
public class ProductMetadata
{
[ScaffoldColumn(true)]
public object ProductID;
[ScaffoldColumn(false)]
public object ThumbnailPhotoFileName;
}
And about RegularExpressionAttribute Class you can read here.
using System;
using System.Web.DynamicData;
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}
public class CustomerMetaData
{
// Allow up to 40 uppercase and lowercase
// characters. Use custom error.
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$",
ErrorMessage = "Characters are not allowed.")]
public object FirstName;
// Allow up to 40 uppercase and lowercase
// characters. Use standard error.
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$")]
public object LastName;
}
We manage several ASP.NET MVC client web sites, which all use a data annotation like the following to validate customer email addresses (I haven't included the regex here, for readability):
[Required(ErrorMessage="Email is required")]
[RegularExpression(#"MYREGEX", ErrorMessage = "Email address is not valid")]
public string Email { get; set; }
What I would like to do is to centralise this regular expression, so that if we make a change to it, all of the sites immediately pick it up and we don't have to manually change it in each one.
The problem is that the regex argument of the data annotation must be a constant, so I cannot assign a value I've retrieved from a config file or database at runtime (which was my first thought).
Can anyone help me with a clever solution to this—or failing that, an alternative approach which will work to achieve the same goal? Or does this just require us to write a specialist custom validation attribute which will accept non-constant values?
The easiest way is to write a custom ValidationAttribute that inherits from RegularExpressionAttribute, so something like:
public class EmailAttribute : RegularExpressionAttribute
{
public EmailAttribute()
: base(GetRegex())
{ }
private static string GetRegex()
{
// TODO: Go off and get your RegEx here
return #"^[\w-]+(\.[\w-]+)*#([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?$";
}
}
That way, you still maintain use of the built in Regex validation but you can customise it. You'd just simply use it like:
[Email(ErrorMessage = "Please use a valid email address")]
Lastly, to get to client side validation to work, you would simply add the following in your Application_Start method within Global.asax, to tell MVC to use the normal regular expression validation for this validator:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(EmailAttribute), typeof(RegularExpressionAttributeAdapter));
Checkout ScotGu's [Email] attribute (Step 4: Creating a Custom [Email] Validation Attribute).
Do you really want to put the regex in database/config file, or do you just want to centralise them? If you just want to put the regex together, you can just define and use constants like
public class ValidationRegularExpressions {
public const string Regex1 = "...";
public const string Regex2 = "...";
}
Maybe you want to manage the regexes in external files, you can write a MSBuild task to do the replacement when you build for production.
If you REALLY want to change the validation regex at runtime, define your own ValidationAttribute, like
[RegexByKey("MyKey", ErrorMessage = "Email address is not valid")]
public string Email { get; set; }
It's just a piece of code to write:
public class RegexByKeyAttribute : ValidationAttribute {
public RegexByKey(string key) {
...
}
// override some methods
public override bool IsValid(object value) {
...
}
}
Or even just:
public class RegexByKeyAttribute : RegularExpressionAttribute {
public RegexByKey(string key) : base(LoadRegex(key)) { }
// Be careful to cache the regex is this operation is expensive.
private static string LoadRegex(string key) { ... }
}
Hope it's helpful: http://msdn.microsoft.com/en-us/library/cc668224.aspx
Why not just write you own ValidationAttribute?
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationattribute.aspx
Then you can configure that thing to pull the regex from a registry setting... config file... database... etc... etc..
How to: Customize Data Field Validation in the Data Model Using Custom