What is the difference between Model, PropertyModel and CompoundPropertyModel in Wicket? - wicket

I have started learning Wicket framework and I came across wicket models and I read about Model(), CompouneModel() and CompoundPropertyModel() but I didn't get the actual difference between them. I searched on Google for this, but I didn't get any information about this.
This link gives description between CompoundPropertyModel and PropertyModel but still its not clear properly for difference.
Only the thing I could distinguish between Model and other two is model can not work with dynamic fields while other two can.
Can someone please give the difference between these models?

All of them are implementations of the interface IModel.
Class Model is a basic implementation, that is almost just a 'data holder' so you can store an object in that model and get. The added value of this class is to forward to get and to set model object if the stored object is an other model (IModel).
Class PropertyModel is useful if you want to get / to set a property using property expression. See an example:
class Data {
private Integer data;
private String name;
/* getters and setters */
}
How to get and set data using the PropertyModel:
Data data = new Data();
data.setId(1);
data.setName("data entity");
IModel idModel = new PropertyModel(data, "id");
IModel nameModel = new PropertyModel(data, "name");
System.out.println(data.getId());
// prints '1'
System.out.println(idModel.getObject());
// prints '1'
System.out.println(data.getName);
// prints 'data entity'
System.out.println(nameModel.getObject());
// prints 'data entity'
data.setId(2);
nameModel.setObject("a new name");
System.out.println(data.getId());
// prints '2'
System.out.println(idModel.getObject());
// prints '2'
System.out.println(data.getName());
// prints 'a new name'
System.out.println(nameModel.getObject());
// prints 'a new name'
Class CompoundPropertyModel is useful if you want to propage properties to the components by their IDs. See an example (using the same class Data):
Java Code (MyPanel.java):
class MyPanel extends Panel {
public MyPanel(IModel<Data> model) {
super(new CompoundPropertyModel<Data>(model));
add(new Label("id"));
add(new Label("data"));
}
}
Markup (MyPanel.html):
<wicket:panel>
<span wicket:id="id">placeholer for id</span>
<span wicket:id="name">placeholer for id</span>
</wicket:panel>
Java Code using MyClass:
// in a Page, Panel or an other Component
Data data = new Data();
data.setId(3);
data.setName('my name');
add(new MyPanel(Model.of(data)));
Rendered output HTML (by the panel):
<span>3</span>
<span>my name</span>

Please check https://cwiki.apache.org/confluence/display/WICKET/Working+with+Wicket+models. It gives very good explanations.
You can also read the official docs at http://ci.apache.org/projects/wicket/guide/6.x/guide/modelsforms.html

Very good example. Just need some correction:
According to
IModel idModel = new PropertyModel(data, "id");
and
private Integer data;
I expect that In Data class supposed to be
private Integer id;
instead.
And the same mistake in next place
add(new Label("data"));
expect
add(new Label("name"));
to make everything correct. Thank you for your help.

Related

JSF: store form data to a map

I'm developing a JSF page that contains a form with a lot of input string values. I don't want to create a corresponding field in the bean for each input . Is it possible to use a map instead.
Here's what i want my form input element to look like:
<h:inputText value='#{myBean.data["key"]}' /> // or something like this
And the bean contains the map as follows:
class myBean {
Map data;
...
}
What should getter and setter for map operation look like if I create such a code?
Nothing special. Just a standard getter as you should always use for model properties.
public Map<String, Object> getData() {
return data;
}
A setter is not mandatory as it won't be used anyway. EL will use map's own put() method for that. You only need to make sure that the map is already precreated in bean's (post)constructor, JSF/EL won't do that for you.
public MyBean() {
data = new HashMap<String, Object>();
}

Saving a Hashtable using Mongo & the Play framework?

I've got a model defined like the following...
#MongoEntity
public class Ent extends MongoModel{
public Hashtable<Integer, CustomType> fil;
public int ID;
public Ent(){
fil = new Hashtable<Integer, CustomType>();
}
}
CustomType is a datatype I've created which basically holds a list of items (among other things). At some point in my web application I update the hashtable from a controller and then read back the size of the item I just updated. Like the following...
public static void addToHash(CustomType type, int ID, int key){
//First I add an element to the list I'm storing in custom type.
Ent ent = Ent.find("byID",ID).first();
CustomType element = user.fil.get(key);
if(element == null) element = new CustomType();
element.add(type);
ent.save();
//Next I reset the variables and read back the value I just stored..
ent = null;
ent = User.find("byID",ID).first();
element = ent.fil.get(ID);
System.out.println("SIZE = " + element.size()); //null pointer here
}
As you can see by my above example I add the element, save the model and then attempt to read back what I have just added and it has not been saved. The above model Ent is a minimal version of the entire Model I'm actually using. All other values in the model including List's, String's, Integer's etc. update correctly when they're updated but this Hashtable I'm storing isn't. Why would this be happening and how could I correct it?
You should probably post on the play framework forum for better help..
Alternatives for a mongodb framework are morphia and springdata which have good documentation.
Not sure how Play maps a hash table to a document value, but it seems it cannot update just the hash table using a mongo operator.
You should be able to mark the whole document for update which would work but slower.

Wicket - Wrapped collection Model "transformation"

I have a domain object which has a collection of primitive values, which represent the primary keys of another domain object ("Person").
I have a Wicket component that takes IModel<List<Person>>, and allows you to view, remove, and add Persons to the list.
I would like to write a wrapper which implements IModel<List<Person>>, but which is backed by a PropertyModel<List<Long>> from the original domain object.
View-only is easy (Scala syntax for brevity):
class PersonModel(wrappedModel: IModel[List[Long]]) extends LoadableDetachableModel[List[Person]] {
#SpringBean dao: PersonDao =_
def load: List[Person] = {
// Returns a collection of Persons for each id
wrappedModel.getObject().map { id: Long =>
dao.getPerson(id)
}
}
}
But how might I write this to allow for adding and removing from the original List of Longs?
Or is a Model not the best place to do this translation?
Thanks!
You can do something like this:
class PersonModel extends Model<List<Person>> {
private transient List<Person> cache;
private IModel<List<String>> idModel;
public PersonModel( IModel<List<String>> idModel ) {
this.idModel = idModel;
}
public List<Person> getObject() {
if ( cache == null ) {
cache = convertIdsToPersons( idModel.getObject() );
return cache;
}
public void setObject( List<Person> ob ) {
cache = null;
idModel.setObject( convertPersonsToIds( ob ) );
}
}
This isn't very good code but it shows the general idea. One thing you need to consider is how this whole thing will be serialised between requests, you might be better off extending LoadableDetachableModel instead.
Another thing is the cache: it's there to avoid having to convert the list every time getObject() is called within a request. You may or may not need it in practice (depends on a lot of factors, including the speed of the conversion), but if you use it, it means that if something else is modifying the underlying collection, the changes may not be picked up by this model.
I'm not quite sure I understand your question and I don't understand the syntax of Scala.
But, to remove an entity from a list, you can provide a link that simply removes it using your dao. You must be using a repeater to populate your Person list so each repeater entry will have its own Model which can be passed to the deletion link.
Take a look at this Wicket example that uses a link with a repeater to select a contact. You just need to adapt it to delete your Person instead of selecting it.
As for modifying the original list of Longs, you can use the ListView.removeLink() method to get a link component that removes an entry from the backing list.

Checking for duplicate values in a Model class

I have a model, Entity, and I built an EntityMapper and an Entity class (I'm just learning to use Zend Framework and following the tutorials). The Entity class has a setName method, and what I want it to do is check if there is another "entity" in the DB with the same name, and in that case throw an exception or something.
So, If I understand correctly, DB calls should only be in the Mapper class. So, inside setName, should I do something like:
$entity = new Application_Model_EntityMapper();
if ($entity->checkDuplicateName($name, $this->_id))
$this->_name = $name;
else
throw new Exception(...);
return $this;
and put the code that actually does the query in a new method in the Mapper class? (the query should, of course, be different if the "entity" is new or if it has an id already, but that's not the point of my question).
I know I could do this in a couple of ways, but my goal is to adjust as much as possible to the conventions of the framework.
Since saving is a duty of the Mapperobject I'd add the validation to the save routine of your mapper class.
I didn't understand what respective duties your different classes have, so I'll explain mine:
-Application_Model_Entity is a pure struct for data, this class has no dependencies
-Application_Model_EntityMapper posses the right to speak with the dbrms, will transform Entities in Records and vice versa. It "owns" the ActiveRecord (DbTable) class
-Application_Model_DbTable_Entity is the ActiveRecord class, it extends from Zend_DbTable_Abstract and is capable of doing queries against the DB, it is only used by the Mapper.
$entity = new Application_Model_Entity();
$entity->setName('something which already exists');
$mapper = new Application_Model_EntityMapper();
$mapper->save($entity); // throws Exception
// works with:
class Application_Model_EntityMapper
{
/** #var Application_Model_DbTable_Entity */
private $dbTable;
...
public function save(Application_Model_Entity $entity)
{
$doValidation = ! $entity->getId(); // no id means not in db yet
if ( $doValidation )
{
$hasDuplicatesValidator = new Zend_Validate_Db_RecordExists(
'table' => 'entity',
'field' => 'name'
);
$hasDuplicates = $hasDuplicatesValidator->isValid($entity->getName());
if ( $hasDuplicates )
{
throw new Exception('There is already a record in the db with this name!');
}
}
// go on and save
$this->dbTable->save($entity);
}
}
I hope the code explains itself.
This is the most 'zendish' way i can find, hope this helps you on your way to the zf-community :)
Link to manual for Zend_Validate_*
I found that doing that check in setName causes it to run the query every time it loads a record from the db (not good), so I moved the call to checkDuplicateName to the save method of the Mapper class. (checkDuplicateName is also on the Mapper class, as a private method now)
I would still love to know if this is the standard way of doing this kind of stuff in Zend Framework.

Read DataAnnotations from a collection of models in an MCV2 view

In my MVC2 AdminArea I'd like to create an overview table for each of my domain models.
I am using DataAnnotations like the following for the properties of those domain model objects:
[DisplayName("MyPropertyName")]
public string Name { get; set; }
Now my question is: How can I access the DisplayName Attribute if my view receives a collection of my domain models? I need this to build the table headers which are defined outside of the usual
<% foreach (var item in Model) { %>
loop. Inside this loop I can write
<%: Html.LabelFor(c => item.Name) %>
but is there any way to access this information using the collection of items instead of a concrete instance?
Thanks in advance!
There is a ModelMetaData class that has a static method called FromLambdaExpression. If you call it and pass in your property, along with your ViewData, it will return an instance of ModelMetaData. That class has a DisplayName property that should give you what you need. You can also get other meta data information from this object.
For example, you can create an empty ViewDataDictionary object to get this information. It can be empty because the ModelMetaData doesn't actually use the instance, it just needs the generic class to define the type being used.
//This would typically be just your view model data.
ViewDataDictionary<IEnumerable<Person>> data = new ViewDataDictionary<IEnumerable<Person>>();
ModelMetadata result = ModelMetadata.FromLambdaExpression(p => p.First().Name, data);
string displayName = result.DisplayName;
The First() method call doesn't break even if you have no actual Person object because the lambda is simply trying to find the property you want the meta data about. Similarly, you could d this for a single Person object:
//This would typically be just your view model data.
ViewDataDictionary<Person> data = new ViewDataDictionary<Person>();
ModelMetadata result = ModelMetadata.FromLambdaExpression(p => p.Name, data);
You could clean this up significantly with a helper or extension method, but this should put you on the right path.
Alright, I followed sgriffinusa's advise (thanks again!) and created a strongly typed HtmlHelper:
public static MvcHtmlString MetaDisplayName<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression) where TModel : class
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
return MvcHtmlString.Create(metadata.GetDisplayName());
}
Of course TModel still is a collection of domain models like stated in my inital question but we can call the helper in the view like this:
<%: Html.MetaDisplayName(p => p.First().Name) %>