Binding a label to an object property - object

I am doing an intro to as project where I have a class, Einstein, that has a property of name. The name property is private, but I have getters and setters for it. In the mxml file, I have a label and a button. The label displays the Einstein object's name. When the button is clicked, the name of the Einstein object is changed. Since the label is binded to the name property, it should update but it is not. Below is the portions of the Einstein as file and the mxml file that could possibly have anything to do with the problem.
[Bindable]
public class Einstein
{
private var name:String;
public function Einstein(name:String)
{setName(name);}
public function getName():String
{return name;}
public function setName(sentName:String):void
{this.name = sentName;}
}
<![CDATA[
[Bindable]
var pEinstein: Einstein = new Einstein("Brighid");
]]>
<s:Label id="nameTag" text="{pEinstein.getName()}" fontSize="24"/>
<s:Button content="change the name">
<s:click>
pEinstein.setName("Freyja");
</s:click>
tldr; my label isn't updating when it is supposed to

I usualy do not work in flex, but try this:
(actual getter/setter AS3 syntax)
public class Einstein
{
private var _name:String;
public function Einstein(name:String)
{setName(name);}
public function get name():String
{return _name;}
public function set name(value:String):void
{_name = value;}
}
and
<![CDATA[
[Bindable]
var pEinstein: Einstein = new Einstein("Brighid");
]]>
<s:Label id="nameTag" text="{pEinstein.name}" fontSize="24"/>
<s:Button content="change the name">
<s:click>
pEinstein.setName("Freyja");
</s:click>

Automatic binding does not work for 'normal' methods. It does for getters/setters, but you'll need to use actionscript syntax for getters and setters. (your get/set functions look like the syntax as I'd use in java - this does work in actionscript, but they won't be recognized as get/set by the mxml compiler)
Change your get/set functions to this:
public function get name():String
{return name;}
public function set name(sentName:String):void
{this.name = sentName;}
Change your call in the click handler to:
pEinstein.name = "Freyja";
And change the label to:
<s:Label id="nameTag" text="{pEinstein.name}" fontSize="24"/>

Related

Implement autocomplete (typeahead with inputText) with BootsFaces

I develop a web application in Java EE, in this one there is an inputText allowing to search for a student according to his name.
However, I am faced with a problem that I cannot find the solution to.
I use an inputText with a typeahead (Bootsfaces), if I send it a List Etudiant (My List Object) it works however when I send it a List String no suggestion appears:/
In my controller (Java), I return a List containing the name and surname of each student and I would like to be able to make appear the suggestion of this list.
There is my xHtml code :
<b:inputText style="width:200px" value="" placeholder="Rechercher étudiant" typeahead="true" typeahead-values="#{etudiantController.getEtudiants()}"/>
There is my Controller (etudiantController) code :
public List<String> getEtudiants() {
etudiants = gestionEtudiant.selectAll();
List<String> listeNomPrenom = new ArrayList<String>();
for(Etudiant e : etudiants) {
listeNomPrenom.add(e.getNom() + " " + e.getPrenom());
}
return listeNomPrenom;
}
I hope not to disturb with my post, thanks in advance ;)
So there are several things to address here...
First of all, you need a backing bean value in order for the component to have a proper reference value. Not setting value might work for the auto completion depending on how the component is implemented, but you won't have access to what the user actually entered later in your controller. With some components it might make the component function in an undesirable way. So you need to connect it to a bean property.
Secondly, typeahead-values is expecting either a straight up string, or a bean property. Only in very special circumstances will you ever need to call the getter of a bean property - so you should reference the property.
Thirdly, instead of returning a new list of students, try to take advantage of Java's built in toString() functionality in your typeahead-values. Then you don't have to create a completely new list, but instead can rely on Java doing the conversion for you.
So a complete solution mimicing what you are trying to do and translated to English would look like this;
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Autocomplete test</title>
</h:head>
<h:body>
<h:form>
<b:inputText value="#{studentBean.studentEntry}" placeholder="Search student"
typeahead="true" typeahead-values="#{studentBean.students}"/>
</h:form>
</h:body>
</html>
#Data
#Named
#ViewScoped
public class StudentBean implements Serializable {
private List<Student> students;
private String studentEntry;
#PostConstruct
public void init() {
students = new ArrayList<>();
students.add(new Student("Carl", "Sagan"));
students.add(new Student("Enrico", "Fermi"));
students.add(new Student("Jay", "Miner"));
}
#Data
#AllArgsConstructor
public class Student {
private String firstName;
private String lastName;
#Override
public String toString() {
return String.format("%s %s", lastName, firstName);
}
}
}
Note that this example uses Lombok - so the #Data annotation creates the needed setters and getters for the properties.
Also notice how toString() actually flips the name and puts the surname first
just like you do in your code.

Xpages ObjectData Custom Control: Mixing compositeData with text

Would like to make a custom control for my DataObjects which would have two properties, the javaClass and the javaModel.
So if I have a java class names acme.com.model.Person, the javaClass property would be acme.com.model.Person and the javaModel property would be Person.
I started to build my custom control but only got a few things put in before I ran into syntactical problems.
The real problem is createObject. I don't understand how I can replace the presently hard-coded "Person" in the createObject with my compositeData values. Is this even possible?
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:this.data>
<xe:objectData
saveObject="#{javascript:compositeData.javaModel + 'save()'}"
var="${javascript:compositeData.javaModel}">
<xe:this.createObject><![CDATA[#{javascript:var Person = new com.scoular.model.Person();
var unid = context.getUrlParameter("key")
if (unid != "") {
Person.loadByUnid(unid);
viewScope.put("readOnly","Yes");
} else {
Person.create();
viewScope.put("readOnly","No");
}
return Person;}]]></xe:this.createObject>
</xe:objectData>
</xp:this.data>
</xp:view>
Just as you might try to de-couple your business logic from your "UI" (XPages markup), you could move your "create" code to a constructor method to the Person class, one which:
calls out to check for the URL Parameter of "key"
sets the key to a property (making this a bit more bean-like, optional, but likely a good idea)
invokes the loadByUnid(String) method
and puts the appropriate readOnly value into viewScope
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
// constructor method
public Person(){
Map<String, Object> reqParm = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String unid = (String) reqParm.get("key");
Map<String, Object> vwScope = ExtLibUtil.getViewScope();
if (unid != "") {
this.loadByUnid(unid);
vwScope.put("readOnly","Yes");
} else {
this.create();
viewScope.put("readOnly","No");
}
}
//...
}
Then your createObject block would look more like:
<xe:this.createObject><![CDATA[#{javascript:return new com.scoular.model.Person();}]]></xe:this.createObject>
This should shift enough of the specifics off of the markup layer so as to be far more reusable across specific classes, provided each self-construct like that.
As for the general mixing compositeData with text, you should be passing an object reference so for the example of the save method above, I think you should be able to access it more via compositeData.javaModel.save();, provided the save method exists in the object referenced by compositeData.javaModel. I don't think appending the string of a method will work, but I can't say I've tried it that way.

WU app XAML binding to Button grid from custom collection

I'm quite new to XAML trying to make grid with Toggle buttons
Something like this:
<GridView ItemSource="{Binding ButtonCollection}">
<GridView.ItemTemplate>
<DataTemplate>
<ToggleButton Content="{Binding Label}" IsEnabled="{Binding BEnabled}" IsChecked="{Binding BChecked, Mode=TwoWay}"/>
<DataTemplate>
</GridView.ItemTemplate>
</GridView>
I have
ObservableCollection<ButtonClass> ButtonCollection
also class for buttons
class ButtonClass
{
public string Label {get; set;}
public bool BEnabled {get; set:}
public bool BChecked {get;set;}
}
binding works when page loads buttons are displayed from ObservableCollection
But I want collection to update when button IsChecked value changes
also is there any way to bind function to click method like:
Click="{Binding DoWhenClicked}"
Now it just results in error I think that is because DoWhenClicked isn't in ItemSource.
Summary:
I want to have Grid of toggle buttons that binds to some sort of list/array/collection of data with label, checked status, enabled status.
When toggle button is checked I want it to reflect in my collection.
Also I want to bind event to Click method so that i can perform operations like disable some Toggle Buttons when other button is checked.
What is good way to do this.
I noticed that you asked several question about Template 10 before, so I supposed that you also used Template 10 here for MVVM pattern.
binding works when page loads buttons are displayed from ObservableCollection But I want collection to update when button IsChecked value changes
In Template 10 project, if you want to get notified when parameter in the data model (here means your ButtonClass), you can derive your class from BindableBase. If you check the BindableBase class you will find that it has done the work of INotifyPropertyChanged, it will be much easier here deriving from BindableBase directly rather than implementing INotifyPropertyChanged by yourself.
also is there any way to bind function to click method
Also I want to bind event to Click method so that i can perform operations like disable some Toggle Buttons when other button is checked.
Instead of Click event, I personally recommend you to using Command in MVVM pattern, and you may want to know which Button is clicked, so you can use CommandParameter here. I created a blank template 10 project and here is my sample:
<GridView x:Name="gridView" RelativePanel.Below="pageHeader" Margin="16,12,0,0" ItemsSource="{x:Bind ViewModel.ButtonCollection}">
<GridView.ItemTemplate>
<DataTemplate>
<ToggleButton Width="100" Content="{Binding Label}" IsEnabled="{Binding BEnabled}"
IsChecked="{Binding BChecked, Mode=TwoWay}" Command="{Binding ToggleBtnClickCommand}"
CommandParameter="{Binding Label}" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The ButtonClass is like this:
public class ButtonClass : BindableBase
{
public string Label { get; set; }
public bool BEnabled { get; set; }
private bool _bChecked;
public bool BChecked
{
get { return _bChecked; }
set
{
_bChecked = value;
RaisePropertyChanged();
}
}
public ICommand ToggleBtnClickCommand { get; set; }
}
And the MainPageViewModel:
public class MainPageViewModel : ViewModelBase
{
public ObservableCollection<ButtonClass> ButtonCollection;
public MainPageViewModel()
{
ButtonCollection = new ObservableCollection<ButtonClass>();
for (int i = 0; i < 20; i++)
{
ButtonCollection.Add(new ButtonClass
{
Label = "TButton " + i,
BChecked = true,
BEnabled = true,
ToggleBtnClickCommand = new DelegateCommand<string>(ToggleBtnClicked)
});
}
}
public void ToggleBtnClicked(string obj)
{
var buttonLable = obj;
}
}
In case you need to check my sample, you can find my demo here.
There are a few concepts that are missing from your code that you need to properly implement for this to work
INotifyPropertyChanged -> Your ButtonClass class acts as a view model for your view. As such, for values to properly update UI and the other way around you need your class to implement it and all your properties to raise the PropertyChanged event when their values change (in the setter)
2-Way bindings -> If you want your ButtonClass instance to update when you click the button and you want your button to change state if you change the property in the ButtonClass, your bindings need to be Mode=TwoWay. You might want to explore the new Bindings {x:Bind} for better performance
Commands -> To bind the click event, you need to use the Command property. You would need to create a ICommand implementation, and create a property in your ButtonClass. The use Command property of the Button to bind to that Command.
Essentially, everything I mentioned are components of an MVVM framework, of which there are many out there. Here are some of the more popular ones: Caliburn, MVVMCross, Prism.
There's also a great starter kit for Windows 10 that will definitely kick start your app and contains a lot of this classes already built - Template10

Access static property in JSF

I have a static List of Select Items in one of my backing beans:
private static List<SelectItem> countries = new ArrayList<SelectItem>();
with the following getters and setters:
public static List<SelectItem> getCountries() {
return countries;
}
public static void setCountries(List<SelectItem> countries) {
LoadSelectItemsBean.countries = countries;
}
I am having trouble with accessing the static List through my XHTML page. The code I have tried is as follows:
<ace:simpleSelectOneMenu id="countryField"
value="#{generalCarrierDataViewBean.carrierBean.countryId}">
<f:selectItems value="#{loadSelectItemsBean.countries}" />
<ace:ajax />
</ace:simpleSelectOneMenu>
The problem line is:
<f:selectItems value="#{loadSelectItemsBean.countries}" />
The exception which results is:
javax.el.PropertyNotFoundException: /pages/GeneralCarrierData.xhtml #394,64 value="#{loadSelectItemsBean.states}": Property 'states' not found on type com.oag.reference.util.LoadSelectItemsBean
Can anbody advise on how to correctly reference a static property from a backing bean?
Thanks
Properties are per definition not static. So getters and setters can simply not be static, although they can in turn reference a static variable. But the outside world does not see that.
You've 3 options:
Remove the static modifier from the getter. The whole setter is unnecessary, you can just remove it.
public List<SelectItem> getCountries() {
return countries;
}
Create an EL function if you really insist in accessing static "properties" (functions). Detail can be found in this answer: How to create a custom EL function to invoke a static method?
Turn the whole List<SelectItem> thing into an enum and make use of OmniFaces <o:importConstants>. Detail can be found in this answer: How to create and use a generic bean for enums in f:selectItems?
Just create a non-static method that returns the static property:
// here you have a static String
private static String static_str;
public static String getStatic_str() {
return static_str;
}
// in jsf page: #{myClass.str}
public String getStr() {
return static_str;
}

Sample for for an XSP Object data source that is writable

I'm struggling with the Object datasource in an XPage:
<xp:this.data>
<xe:objectData var="demo" ignoreRequestParams="true"
readonly="false" scope="view"
createObject="#{javascript:return new demo.SampleBean();}">
</xe:objectData>
</xp:this.data>
When I execute save(); on the XPage in SSJS I get the error:
Error saving data source demo
The save method has not been implemented in the data source
The class is rather simple:
package demo;
import java.io.Serializable;
public class SampleBean implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String job;
public String getName() {
return this.name;
}
public String getJob() {
return this.job;
}
public void setName(final String name) {
this.name = name;
}
public void setJob(final String job) {
this.job = job;
}
public void dummyAction() {
System.out.println("Here shall be logic");
}
}
I tried to add a public void save(); method to the class, but that doesn't do the trick.
So I'm looking for a sample of an Object datasource
You've defined the createObject attribute for the data source, but you haven't specified the saveObject attribute... that's what the error message you're getting ("save method has not been implemented") is referring to.
So, for example, if you want your dummyAction() method to run when a save is triggered, try this:
<xp:this.data>
<xe:objectData var="demo" ignoreRequestParams="true"
readonly="false" scope="view"
createObject="#{javascript:return new demo.SampleBean();}"
saveObject="#{javascript:return value.dummyAction();}">
</xe:objectData>
</xp:this.data>
When the saveObject attribute is specified as a SSJS method binding, the variable value is bound to the data object, and then the method binding is invoked. So you can either pass value to some other object to handle the business logic of saving the object, or you can use a syntax of value.anyMethod() to keep the business logic of object serialization internal to the object itself.
NOTE: whatever logic you do use in this method, you'll want to return a boolean (not void), so that a return value of false can be treated as a cancellation, just like the standard Domino document data source does.

Resources