I'm a newbie to Wix burn. I'm making a wix Bootstrapper Application (BA) with multiple msi to install and an UI consisting of one panel with checkboxes and a button install. Each checkbox invites the user to select/unselect a msi, then the user presses "Install" and my BA should install the checked msi.
In my Chain element in the main .wxs file, I plan to use MsiPackage elements with a condition attribute to determine whether yes or no the user has selected it.
Now my question is : how to interface these condition attributes with the checkboxes ? Or in other words: how to get the checkbox information into the Wix .wxs file ?
I can explain how I do it. May there's a better way.
My checkBoxes are bound to properties in a ViewModel class. When a checkBox value is changed in the setter of the property I set the value of a variable
defined in the Bundle.wxs file.
private bool _installApp1Checked;
public bool InstallApp1Checked
{
get { return _installApp1Checked; }
set
{
_installApp1Checked = value;
if (value == true)
{
Bootstrapper.Engine.StringVariables["InstallApp1"] = "1";
}
else
{
Bootstrapper.Engine.StringVariables["InstallApp1"] = string.Empty;
}
RaisePropertyChanged("InstallApp1Checked");
}
}
private bool _installApp2Checked;
public bool InstallApp2Checked
{
get { return InstallApp2Checked; }
set
{
_installApp2Checked = value;
if (value == true)
{
Bootstrapper.Engine.StringVariables["InstallApp2"] = "1";
}
else
{
Bootstrapper.Engine.StringVariables["InstallApp2"] = string.Empty;
}
RaisePropertyChanged("InstallApp2Checked");
}
}
private bool _installApp3Checked;
public bool InstallApp3Checked
{
get { return _installApp3Checked; }
set
{
_installApp3Checked = value;
if (value == true)
{
Bootstrapper.Engine.StringVariables["InstallApp3"] = "1";
}
else
{
Bootstrapper.Engine.StringVariables["InstallApp3"] = string.Empty;
}
RaisePropertyChanged("InstallApp3Checked");
}
}
And in the Bundle.wxs I have:
<Wix ...>
<Bundle ...>
...
<Chain>
...
<MsiPackage>
...
<MsiProperty Name="InstallApp1" Value="[InstallApp1]"/>
<MsiProperty Name="InstallApp2" Value="[InstallApp2]"/>
<MsiProperty Name="InstallApp3" Value="[InstallApp3]"/>
...
</MsiPackage>
</Chain>
</Bundle>
</Wix>
By using the tag the properties of the ViewModel class are available in the wsx file.
Then these values are available at the moment of the installation in my product.wxs:
<Product >
...
<Property Id="InstallApp1">
</Property>
<Property Id="InstallApp2">
</Property>
<Property Id="InstallApp3">
</Property>
<Feature Id="ProductFeature" Title="Alvenos" Level="0">
<ComponentRef Id="ProductComponents" />
<Condition Level="1">InstallApp1</Condition>
</Feature>
<Feature Id="AlvenosVSIXFeature" Title="Alvenos" Level="0">
<ComponentRef Id="AlvenosVsix" />
<Condition Level="1">InstallApp2</Condition>
</Feature>
<Feature Id="AlvenosServerVSIXFeature" Title="Alvenos" Level="0">
<ComponentRef Id="AlvenosServerVsix" />
<Condition Level="1">InstallApp3</Condition>
</Feature>
...
</Product>
You can see the the default value of the Level attribute of the Feature tag is set to 0. That means that the app will not be istalled.
But if in the Condition tag InstallApp[1],[2] or [3] is set 1 the Level is set to 1 and the app is installed.
Use ComponentRef to refernce a Component tag that will contain information about the destination folder of the app that you will install.
<Fragment>
<ComponentGroup Id="InstallApp1" Directory="[target directory id]>
<Component Id="ProductComponent">
<File Source="[your app part of the installer]" />
</Component>
...
</Fragment>
I hope you get the idea.
Related
I have list of check boxes inside rich:dataTable and I want to check all the boxes at once with a single check box from header column.
<rich:column id="includeInWHMapping" >
<f:facet name="header">
<h:selectBooleanCheckbox value="#{checkallbox.selectAll}">
<f:ajax actionListener="#{checkallbox.selectAllBox}" render="selectedForWHProcess" />
</h:selectBooleanCheckbox>
</f:facet>
<h:selectBooleanCheckbox id="selectedForWHProcess" value="#{checkallbox.checked[data]}">
<f:ajax actionListener="#{checkallbox.selectAllRows}"/>
</h:selectBooleanCheckbox></rich:column>
Code in checkallbox Bean:
private Map<StandardStructure, Boolean> checked = new HashMap<StandardStructure, Boolean>();
private boolean selectAll;
public boolean isSelectAll() {
return selectAll;
}
public void setSelectAll(boolean selectAll) {
this.selectAll = selectAll;
}
public Map<StandardStructure, Boolean> getChecked() {
return checked;
}
public void setChecked(Map<StandardStructure, Boolean> checked) {
this.checked = checked;
}
public void selectAllBox(ValueChangeEvent e){
boolean newSelectAll = (Boolean) e.getNewValue();
Iterator<StandardStructure> keys = checked.keySet().iterator();
while(keys.hasNext()){
StandardStructure ss = keys.next();
checked.put(ss, newSelectAll);
}
}
When I check the h:selectBooleanCheckBox of header column nothing happens. What am I missing here? Should I have to implement Map for "selectAll" property too?
Thanks.
First of all. f:ajax doesn't have actionListener, it has a listener. Read the docs here. Second thing, you can use valueChangeListener on h:selectBooleanCheckbox and only there. Third, listener inside rows boxes is wrong. Basically, it looks like you need to read this topic.
Now, here is the working example:
<h:form>
<rich:dataTable value="#{checkallbox.allValues}" var="data" id="dataTable">
<rich:column>
<f:facet name="header">
<h:selectBooleanCheckbox value="#{checkallbox.selectAll}"
valueChangeListener="#{checkallbox.selectAllBox}">
<f:ajax render="dataTable" />
</h:selectBooleanCheckbox>
</f:facet>
<h:selectBooleanCheckbox value="#{checkallbox.checked[data]}">
<f:ajax />
</h:selectBooleanCheckbox>
</rich:column>
<!-- other columns -->
</rich:dataTable>
</h:form>
Other possible problems with your code (since you've shared just a part).
The data table needs to be in form, since you're executing ajax inside.
Your keys in map are objects. You have to make sure that equals method is good. In 95% of case the default is not, especially if they are #Entity.
You have to make sure that the map is populated with false at the beginning. I use #PostConstruct:
#PostConstruct
protected void performPostConstructAction() {
for (StandardStructure s : getAllValues()) {
checked.put(s, false);
}
}
Thanks Emil! I solved it.
public void selectAllBox(){
if(!selectAll){
for(StandardStructure item : ssTable.getDto()){
checked.put(item, true);
}
}else{
for(StandardStructure item : ssTable.getDto()){
checked.put(item, false);
}
}
}
A combobox is bound to a java bean. Documents is opened in read mode, and the selected value is displayed.
But when I go into Edit mode the value is "lost".
I would like to avoid making two fields on the page, but I guess I can if I must. But it seems like something is wrong with my code or my approach.
<?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"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.afterPageLoad><![CDATA[#{javascript:sessionScope.models = PCConfig.models;
viewScope.readOnly = "Yes";}]]></xp:this.afterPageLoad>
<xp:button value="Toggle Edit Mode" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:if (viewScope.readOnly == "Yes")
{viewScope.readOnly = "No"}
else
{viewScope.readOnly = "Yes"}}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:br></xp:br>
<xp:text escape="true" id="computedField1" value="#{viewScope.readOnly}"></xp:text>
<xp:br></xp:br>
<xp:panel id="pnlAll">
<xp:this.data>
<xe:objectData saveObject="#{javascript:PCModel.save()}"
var="PCModel">
<xe:this.createObject><![CDATA[#{javascript:var pc = new com.scoular.model.PC();
var unid = sessionScope.get("key");
if (unid != null) {
pc.loadByUnid(unid);
sessionScope.put("key","");
viewScope.put("readOnly","Yes");
} else {
pc.create();
viewScope.put("readOnly","No");
}
return pc;}]]></xe:this.createObject>
</xe:objectData>
</xp:this.data>
<xp:comboBox id="model" value="#{PCModel.model}"
disableValidators="true" disableClientSideValidation="true"
styleClass="form-control">
<xp:this.attrs>
<xp:attr name="disabled" value="disabled">
<xp:this.rendered><![CDATA[#{javascript:if (viewScope.readOnly == "Yes")
{return true}
else
{return false}}]]></xp:this.rendered>
</xp:attr>
</xp:this.attrs>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:"--Select A Value--|"}]]></xp:this.value>
</xp:selectItems>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:sessionScope.models}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
</xp:panel>
</xp:view>
Replace your code for setting comboBox's property disabled
<xp:comboBox
id="model"
value="#{PCModel.model}"
...>
<xp:this.attrs>
<xp:attr name="disabled" value="disabled">
<xp:this.rendered><![CDATA[#{javascript:if
(viewScope.readOnly == "Yes")
{return true}
else
{return false}}]]></xp:this.rendered>
</xp:attr>
</xp:this.attrs>
by
<xp:comboBox
id="model"
value="#{PCModel.model}"
...
disabled="#{javascript:viewScope.readOnly == 'Yes'}">
Seems, comboBox can't deal correctly with the disabled setting by attr (whereas it works fine for an inputText control).
But, comboBox's direct property disabled is better to handle than by attrs / attr code anyway.
I am building an Angular 1.3.5 app using Breeze 1.5.1 to interface with a SAP gateway server. One requirement is to minimize duplicate UI translations by re-using the human-readable metadata labels provided by the server. From what I can gather, Breeze's support for custom metadata properties should allow me to load these labels alongside all the standard entity metadata, but I'm struggling to work out exactly how to approach this.
The metadata service provides data in the following format:
<EntityType Name="ContactPersonEmail" sap:content-version="1">
<Key>
<PropertyRef Name="email"/>
</Key>
<Property Name="cpGuid" Type="Edm.Guid" sap:label="Long Text String for XML and HTML Output"/>
<Property Name="primaryEmail" Type="Edm.Boolean" Nullable="false" sap:label="Standard No."/>
<Property Name="email" Type="Edm.String" Nullable="false" MaxLength="241" sap:label="E-Mail Address"/>
<Property Name="homeIndicator" Type="Edm.Boolean" Nullable="false" sap:label="Home address"/>
<Property Name="location" Type="Edm.String" Nullable="false" MaxLength="2" sap:label="Email Type"/>
<Property Name="emailType" Type="Edm.String" Nullable="false" MaxLength="2" sap:label="Email Type"/>
<Property Name="emailTypeText" Type="Edm.String" Nullable="false" MaxLength="60"/>
</EntityType>
where the sap:label attribute is the text I want to add to the Breeze entity type. Is this feasible? The Breeze documentation mostly seems to be focused on loading custom metadata from a local file or already-loaded data, rather than including an additional property on data load, so perhaps this approach is naive.
Once this is resolved I'll work out how to get the text onto the page, but that's for later.
Update: Solution
Per Jeremy's answer below, I was able to run the metadata response through an initialisation function and capture the label field via the metadataProperty's extension property. Example (pre-refactor) code as follows:
// ...
if (entityProperty) {
if (typeof metadataProperty.extensions !== "undefined" && metadataProperty.extensions.length) {
var extension = metadataProperty.extensions[0];
entityProperty[extension.name] = extension.value;
}
}
// ...
The extension.name in this instance is "label", and it's the only extension in the array where it appears. Now all that remains is to get the data onto the UI, but I'm sure that'll be trivial :)
I think this is possible although I'll admit I have only supplemented the Breeze Metadata JSON schema, never XML.
When fetching the metadata on the client you'll just need to do a bit of additional processing to supplement the breeze entity type with your custom metadata properties. In the example code below four custom metadata props are added: displayName, displayOrder, autoGenerateField and allowEmptyStrings.
function initializeMetadataStore(metadataStore, metadata) {
var metadataType, metadataProperty, entityProperty, i, j;
for (i = 0; i < metadata.schema.entityType.length; i++) {
metadataType = metadata.schema.entityType[i];
var entityType = metadataStore.getEntityType(metadataType.name);
for (j = 0; j < metadataType.property.length; j++) {
metadataProperty = metadataType.property[j];
entityProperty = entityType.getProperty(metadataProperty.name);
if (entityProperty) {
if (typeof metadataProperty.displayName !== 'undefined') {
entityProperty.displayName = metadataProperty.displayName;
}
if (typeof metadataProperty.displayOrder !== 'undefined') {
entityProperty.displayOrder = metadataProperty.displayOrder;
}
if (typeof metadataProperty.autoGenerateField !== 'undefined') {
entityProperty.autoGenerateField = metadataProperty.autoGenerateField;
}
if (typeof metadataProperty.allowEmptyStrings !== 'undefined') {
entityProperty.allowEmptyStrings = metadataProperty.allowEmptyStrings;
}
}
}
}
}
var entityManager = ....something...;
entityManager.fetchMetadata(function (metadata) {
return initializeMetadataStore(entityManager.metadataStore, metadata);
});
Here's my answer to a similar question however the OP's backend is .NET and they're using the Breeze Metadata JSON schema.
I'm populating items to a comboBox from an xml file. I'm trying to customize the font-color of each item that appears in the comboBox. Any suggestions?
Thanks!
--Moe
The process is simple if you are using Flash Builder. Each item in your ComboBox is made of an ItemRenderer. Create a custom item render (file - > new -> mxml component) extending that basic ItemRenderer class then assign this new ItemRenderer to your ComboBox. Now inside your custom ItemRenderer you can change values, font sizes, etc ...
You will need to use an ItemRenderer. Though you have not mentioned but it seems you are using Flex 3. The way of using ItemRenderer is slightly different in Flex 3 vs Flex 4. So here is the version for Flex 3:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" minWidth="955" minHeight="600">
<mx:XMLList id="statesXMLList" xmlns="">
<state abbrev="AK" name="Alaska" />
<state abbrev="AZ" name="Arizona" />
<state abbrev="AR" name="Arkansas" />
<state abbrev="CA" name="California" />
<state abbrev="CO" name="Colorado" />
<state abbrev="CT" name="Connecticut" />
</mx:XMLList>
<mx:ComboBox id="comboBox"
prompt="Please select a State..."
dataProvider="{statesXMLList}"
rowCount="3"
labelField="#name"
itemRenderer="ComboBoxItemRenderer"
/>
</mx:Application>
The class for ItemRenderer is ComboBoxItemRenderer which is shown below:
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
lbl.text = value.#name;
if(value.#abbrev == "AK") {
lbl.setStyle("color","#FF0000");
}
else if(value.#abbrev == "AR") {
lbl.setStyle("color","#FF00FF");
}
else {
lbl.setStyle("color","#000000");
}
}
]]>
</mx:Script>
<mx:Label id="lbl"/>
</mx:VBox>
Do not forget the last if (default case) whenever you override set data method.
I am facing trouble to set the path of swfobject. In my project directory structure I put the swfobject.js and loadmovie.js files in the "Project/src/main/webapp/resources" directory. In same directory I placed the test.swf file. The content of loadmovie.js is:
var swfVersionStr = "10.0.0";
var xiSwfUrlStr = "playerProductInstall.swf";
var flashvars = {};
var params = {};
params.wmode = "transparent";
params.quality = "high";
params.allowscriptaccess = "sameDomain";
params.allowfullscreen = "true";
var attributes = {};
attributes.id = "test";
attributes.name = "test";
attributes.align = "left";
swfobject.embedSWF("test.swf", "movieDiv", "202", "380", swfVersionStr, xiSwfUrlStr, flashvars, params, attributes);
swfobject.createCSS("#flashContent", "display:block;text-align:left;");
But the test.swf is not loading the web page. If I view the source of the webpage after rendering the swfobject is transforming as :
<object type="application/x-shockwave-flash" id="test" name="test" align="left" data="test.swf" width="202" height="380">
<param name="wmode" value="transparent">
<param name="quality" value="high">
<param name="allowscriptaccess" value="sameDomain">
<param name="allowfullscreen" value="true">
</object>
And if I replace the data="test.swf" by data="http://localhost/project/resources/test.swf" then swf is visible. Please help. How can I set the path? Thank you
Use absolute paths:
data="/project/resources/test.swf"