How to do this with zk MVVM
i want to save a bean
but with condition
if the type is personal than save into personal, else into company
<textbox value="#save(vm.personal ? vm.masterCifPersonal.cifId : vm.masterCifCompany.cifId)" width="100px" maxlength="10"/>
but when binder save into bean, this exception appear
Illegal Syntax for Set Operation
My tip is to modify your code and use a temporary var:
<textbox value="#save(vm.temp)" width="100px" maxlength="10"/>
and modify your setter as
void setTemp(Long temp) {
if(personal) {
masterCifPersonal.cifId = temp;
} else {
masterCifCompany.cifId = temp;
}
}
another solution could be :
ZK 8 and higher :
<if test="#load(vm.personal)">
<textbox value="#save(vm.masterCifPersonal.cifId)"/>
</if>
<if test="#load(not vm.personal)">
<textbox value="#save(vm.masterCifCompany.cifId)"/>
</if>
ZK 6.5 an higher:
<textbox value="#save(vm.masterCifPersonal.cifId)" visible="="#load(vm.personal)"/>
<textbox value="#save(vm.masterCifCompany.cifId)" visible="="#load(not vm.personal)"/>
Difference:
The if tag will not render the other tag into the dom while using the visible attribute will render it in the dom.
If personal isn't dynamic you could use the if attribute of the Textbox but the usage is then : if="${vm.personal} because binding will not work
Like this the textbox isn't also rendered into the DOM.
Related
i'm trying to get data from multiple tables in liferay 6.0.6 using custom sql, but for now i'm just able to display data from one table.does any one know how to do that.thanks
UPDATE:
i did found this link http://www.liferaysavvy.com/2013/02/getting-data-from-multiple-tables-in.html but for me it's not working because it gives an error BeanLocator is null,and it seems that it's a bug in liferay 6.0.6
The following technique also works with liferay 6.2-ga1.
We will consider we are in the portlet project fooproject.
Let's say you have two tables: article, and author. Here are the entities in your service.xml :
<entity name="Article" local-service="true">
<column name="id_article" type="long" primary="true" />
<column name="id_author" type="long" />
<column name="title" type="String" />
<column name="content" type="String" />
<column name="writing_date" type="Date" />
</entity>
<entity name="Author" local-service="true">
<column name="id_author" type="long" primary="true" />
<column name="full_name" type="String" />
</entity>
At that point run the service builder to generate the persistence and service layers.
You have to use custom SQL queries as described by Liferay's Documentation to fetch info from multiple databases.
Here is the code of your fooproject-portlet/src/main/ressources/default.xml :
<?xml version="1.0"?>
<custom-sql>
<sql file="custom-sql/full_article.xml" />
</custom-sql>
And the custom request in the fooproject-portlet/src/main/ressources/full_article.xml:
<?xml version="1.0"?>
<custom-sql>
<sql
id="com.myCompany.fooproject.service.persistence.ArticleFinder.findByAuthor">
<![CDATA[
SELECT
Author.full_name AS author_name
Article.title AS article_title,
Article.content AS article_content
Article.writing_date AS writing_date
FROM
fooproject_Article AS Article
INNER JOIN
fooproject_Author AS Author
ON Article.id_author=Author.id_author
WHERE
author_name LIKE ?
]]>
</sql>
</custom-sql>
As you can see, we want to fetch author's name, article's title, article's content and article's date.
So let's allow the service builder to generate a bean that can store all these informations. How ? By adding it to the service.xml ! Be careful: the fields of the bean and the fields' name returned by the query must match.
<entity name="ArticleBean">
<column name="author_name" type="String" primary="true" />
<column name="article_title" type="String" primary="true" />
<column name="article_content" type="String" />
<column name="article_date" type="Date" />
</entity>
Note: defining which field is primary here does not really matter as there will never be anything in the ArticleBean table. It is all about not having exceptions thrown by the service builder while generating the Bean.
The finder method must be implemented then. To do so, create the class com.myCompany.fooproject.service.persistence.impl.ArticleFinderImpl. Populate it with the following content:
public class ArticleFinderImpl extends BasePersistenceImpl<Article> {
}
Use the correct import statements and run the service builder. Let's make that class implement the interface generated by the service builder:
public class ArticleFinderImpl extends BasePersistenceImpl<Article> implements ArticleFinder {
}
And populate it with the actual finder implementation:
public class ArticleFinderImpl extends BasePersistenceImpl<Article> implements ArticleFinder {
// Query id according to liferay's query naming convention
public static final String FIND_BY_AUTHOR = ArticleFinder.class.getName() + ".findByAuthor";
public List<Article> findByAuthor(String author) {
Session session = null;
try {
session = openSession();
// Retrieve query
String sql = CustomSQLUtil.get(FIND_BY_AUTHOR);
SQLQuery q = session.createSQLQuery(sql);
q.setCacheable(false);
// Set the expected output type
q.addEntity("StaffBean", StaffBeanImpl.class);
// Binding arguments to query
QueryPos qpos = QueryPos.getInstance(q);
qpos.add(author);
// Fetching all elements and returning them as a list
return (List<StaffBean>) QueryUtil.list(q, getDialect(), QueryUtil.ALL_POS, QueryUtil.ALL_POS);
} catch(Exception e) {
e.printStackTrace();
} finally {
closeSession(session);
}
return null;
}
}
You can then call this method from your ArticleServiceImpl, whether it is to make a local or a remote API.
Note: it is hack. This is not a perfectly clean way to retrieve data, but it is the "less bad" you can do if you want to use Liferay's Service Builder.
Is it possible to bind a form element to a List<Long>?
ie. <form:input path="formValues[0]" /> binding to an element in List<Long> formValues; in the form backing object?
When I try this, it fails because Long does not have a default constructor new Long().
I've worked around it by creating a dummy holder class
class DummyLong {
private Long value;
...
}
making the list in the formbacking object a List<DummyLong> and changing the form tag to <form:input path="formValues[0].value" /> but this seems unnecessarily hideous and I'm sure there must be a better way. Haven't been able to find it though.
Use List<Long> formValues with <form:input path="formValues" />
There are two tables of interest in my entity conceptual model: tblProducts and tblInstalledProducts.
Each installed product has a ProductID foreign key linking it to a specific product, which was set up automatically as a navigation property.
Within the entity domain service I have the following query:
public IQueryable<tblInstalledProduct> GetInstalledProductsBySiteID(string SiteID)
{
ObjectSet<tblInstalledProduct> installedProducts = this.ObjectContext.tblInstalledProducts;
var filterBySite =
from p in installedProducts.Include("tblProduct")
where p.SiteID == SiteID
select p;
return filterBySite;
}
I have a DataGridView bound to a DomainDataSource configured to use this query.
When I debug this query, p.tblProduct and p.tblProductReference are populated as expected. The problem arises when trying to access the tblProduct property of any tblInstalledProduct from the client side.
//Find associated install record for the selected product
tblInstalledProduct selectedInstall =
Context.tblInstalledProducts.Where(
p => p.SiteID == "Site1" && p.ProductID == 38
).First();
string productName = selectedInstall.tblProduct.ProductName;
For some reason tblProduct is always null. I've tried .Include() / .Load() and can't seem to get it to populate itself.
Why is tblInstalledProduct.tblProduct loaded up as expected on the service side of things, but is seemingly inaccessible on the client side?
Thanks for reading.
Edit:
XAML DataSource:
<telerik:RadDomainDataSource x:Key="InstalledProductsDataSource"
Name="InstalledProductsDataSource"
DomainContext="{StaticResource DomainContext}"
AutoLoad="True"
QueryName="GetInstalledProductsInfoBySiteID"
SubmittedChanges="InstalledProductsDataSource_SubmittedChanges">
<telerik:RadDomainDataSource.QueryParameters>
<telerik:QueryParameter
ParameterName="SiteID"
Value="{Binding SelectedValue,ElementName=SiteList}" />
</telerik:RadDomainDataSource.QueryParameters>
</telerik:RadDomainDataSource>
XAML DataGrid:
<telerik:RadGridView x:Name="InstalledProductsGridView"
ItemsSource="{Binding DataView, Source={StaticResource InstalledProductsDataSource}}">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="Product Name" DataMemberBinding="{Binding ProductName, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Version" DataMemberBinding="{Binding ProductVersion, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding Description, Mode=TwoWay}" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
Right now the grid is bound to a collection of tblProducts, but I'd like to bind it to a collection of tblInstalledProducts (as there is some extra information in that table that I need access to) like so:
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="DateInstalled" DataMemberBinding="{Binding DateInstalled, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Product Name" DataMemberBinding="{Binding tblProduct.ProductName, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Version" DataMemberBinding="{Binding tblProduct.ProductVersion, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding tblProduct.Description, Mode=TwoWay}" />
</telerik:RadGridView.Columns>
you need to do something like this
tblInstalledProduct selectedInstall = Context.GetInstalledProductsBySiteID("Site1").Where(p=> p.ProductID == 38 ).FirstOrDefault();
string productName="";
if(selectedInstall !=null)
{
productName= selectedInstall.tblProduct.ProductName;
}
for testing try to use;
public IQueryable<tblInstalledProduct> GetInstalledProductsNew()
{
//Im nut Sure of 'tblProduct' or 'tblProducts' it is dependent on your relations
return this.ObjectContext.tblInstalledProducts.Include("tblProduct");
}
For anyone else having problems with this, I did eventually find the solution. You need to use both .Include() on the query to tell it to load related objects, as well as the [Include] attribute in the metadata to allow those related objects to be serialized and sent to the client.
I am using zk 5.0.3. I want to use the following annotation binding as the title of a "center" region of a borderlayout:
<a:bind content="entrydisplay.activeEntryCaption" /> <html />
I want to do the following:
<borderlayout>
<north title="use the above binding here">
this is north
</north>
</borderlayout>
How do I achieve the functionality such that I can wrap this binding as the value of the title?
Thanks,
Sony
You are using an outdated version of ZK data binding. It is highly recommended that you make use of the latest methodology.
The following link is the databinding section of the ZK Essential guide & Developer's Reference:
Developer's Reference Databinding
ZK Essential's Databinding
Our basic databinding consists of a POJO which follows the Java bean conventions being access from an XML based interface using annotations in attributes. For example:
Person POJO:
public class Person {
private String _firstName = "";
private String _lastName = "";
private Boolean _married = true;
public Person(){
}
public Person(String firstName, String lastName, Boolean married){
_firstName = firstName;
_lastName = lastName;
_married = married;
}
// getter and setters
public void setFullName(String f) {
// do nothing
}
public String getFullName() {
return _firstName + " " + _lastName;
}
//add more here
}
The UI file:
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<window>
<zscript><![CDATA[
//prepare the person object
import bean.Person;
Person person = new Person();
person.setFirstName("Max");
person.setLastName("Planck");
]]>
</zscript>
<grid width="400px">
<rows>
<row> First Name: <textbox value="#{person.firstName}"/></row>
<row> Last Name: <textbox value="#{person.lastName}"/></row>
<row> Full Name: <label value="#{person.fullName}"/></row>
</rows>
</grid>
</window>
The theory is described here.
i think the old way is done it like this
<borderlayout>
<north>
<attribute name="label">
<a:bind value="entrydisplay.activeEntryCaption" />
</attribute>
</north>
</borderlayout>
The new doc
The doc of [http://docs.zkoss.org/wiki/Data_binding][Data Binding]
For your specific question, annotate your component like following:
<borderlayout>
<north id="mynorth" title="#{entrydisplay.activeEntryCaption}">
this is north
</north>
</borderlayout>
Data binder will read such annotation and call the getter and setter methods to set the title of the north component for you. It will do something like:
mynorth.setTitle(entrydisplay.getActiveEntryCaption());
I'm dynamically adding textboxes to a form on my jsp page using Javascript. When that form is submitted to an action, how does my action get the values of those textboxes? (I'm using Struts 2, btw.) In ASP.NET, I was able to find them in Form.Request/FormCollection. Is there a Struts 2 equivalent? Thanks a million.
In Struts2, you create beans in the form to do submit values. In order to create the input text-box, use the <s> tag. For example :
<s:textfield name="loginBean.userName" label="UserName" required="true" />
Here loginBean is the bean passed to the jsp page when.
Bean consists of variable declarations and getters-setters for the variable.
Then in the back-end Java where the form is submitted to, you can access the same bean.
Declare getter-setter in Java and then you can access the properties of the bean.
public LoginBean getLoginBean() {
return loginBean;
}
public void setLoginBean(LoginBean loginBean) {
this.loginBean = loginBean;
}
public String authenticate() {
String username = loginBean.getUserName();
I would recommend looking at source codes of open-source Struts projects.
It sounds like you're trying to populate a dynamic list. To do that, you just have to use the [n] index syntax at the end of your Action class property name:
HTML:
<input type="text" name="yourCollection[0]" value="first value" />
<input type="text" name="yourCollection[1]" value="second value" />
<input type="text" name="yourCollection[2]" value="third value" />
Action Class:
public class YourAction extends Action {
public List<String> yourCollection;
public List<String> getYourCollection(){
return yourCollection;
}
public void setYourCollection(List<String> aCollection){
this.yourCollection = aCollection;
}
}