Child lightning component init execute before parent init salesforce - salesforce-lightning

I have a lightnoing application App which contains a lightning component C1
This component contains an other C2 one which implements 2 dependent picklists
The issue is that C2 needs his attributes value from the C1 component
But since the Child component init (C2) is executed before the parent one init (C1), so the child is not working correctly
Can you please help me?
Thanks

A quick solution to this problem would be instead of using init handler you can use change handler in you C2 component. So, the code will be something like,
({
doAction : function(component, event, helper) {
// Access "data" using standard component.get()
}
})
<!-- C1 component -->
<aura:component>
<aura:attribute name="dataForC2" type="Object"/>
<c:C2 data = "{!v.dataForC2}"/>
</aura:component>
<!-- C2 component -->
<aura:component>
<aura:attribute name="data" type="Object"/>
<aura:handler name="change" value="{!v.data}" action="{!c.doAction}"/>
</aura:component>

To solve this issue you need to create one Boolean attribute for it when init method of parent is done then make that one true so it can go for child init method
Note: use child component inside aura:if in parent component

Related

How to set SinglePlanningCalendar's initial selected calendar view in XML?

I want to use the sap.m.SinglePlanningCalender association selectedView to set the default selected View when a user starts the app:
<SinglePlanningCalendar selectedView="workWeekView">
<views>
<SinglePlanningCalendarDayView id="dayView" key="DayView" title="{i18n>calendarTabMyDay}" />
<SinglePlanningCalendarWorkWeekView id="workWeekView" key="WorkWeekView" title="{i18n>calendarTabMyWorkingWeek}" />
<SinglePlanningCalendarWeekView id="weekView" key="WeekView" title="{i18n>calendarTabMyWeek}" />
<SinglePlanningCalendarMonthView id="monthView" key="MonthView" title="{i18n>calendarTabMyMonth}" />
</views>
<!-- ... -->
</SinglePlanningCalendar>
However, I get the Message in console:
2022-10-26 11:15:16.235500 There is no such view. - Element sap.m.SinglePlanningCalendar#__component0---Calendar--planningCalendar
And the view is not selected.
During the debugging of SinglePlanningCalendar.js in SinglePlanningCalendar.prototype.setSelectedView, I noticed that the SinglePlanningCalendarView instances do not yet exist during the creation of the XML view .
Callstack:
SinglePlanningCalendar.setSelectedView (SinglePlanningCalendar.js:878)
ManagedObject.applySettings (ManagedObject.js?eval:1207)
(anonym) (ManagedObject.js?eval:520)
constructor (ManagedObject.js?eval:535)
constructor (Element.js?eval:200)
constructor (Control.js:181)
fnClass (Metadata.js?eval:454)
(anonym) (XMLTemplateProcessor.js:1644)
So in console sap.ui.getCore().byId("__component0---Calendar--planningCalendar").getViews() at that time returns an empty array and the method runs into an error.
After the complete rendering of the page, sap.ui.getCore().byId("__component0---Calendar--planningCalendar").getViews() returns the array of the SinglePlanningCalendarViews instances.
I know I can set the selected view in controller. However, I was wondering if there is a way to do it in the XML view.

How to synchronize control values within different views

I would like to know how to get the content of TextArea, assign the value to a variable, set it to a model, and then set the variable to another TextArea in another view. I have coded some examples and it works, but not on TextArea.
Here is the example code:
// In init of the Component.js
this.setModel(new JSONModel(), "TransportModel"); // JSONModel required from "sap/ui/model/json/JSONModel"
// In *.controller.js
this.getView().getModel("TransportModel").setProperty("/", {
"Serial": this.byId("mat_serial").getValue() // "mat_serial" == id of the Input box in XML view
});
In the last step, I set the Text from a different View (also XML and Input Box) with the Value of the Model Element.
<Text text="{TransportModel>/Serial}" />
That worked pretty well.
But how to do the same with the TextArea? How can I do it based on this model? The value that I want to use from the first TextArea should also be on a TextArea in another view.
UI5 supports two-way data binding. I.e. if the user changes something in the UI (e.g. user types something in the text area), that change will be reflected automatically in other bindings that listen to the change.
<!-- In view 1 -->
<TextArea value="{TransportModel>/Serial}" />
<!-- In view 2 -->
<Text text="{TransportModel>/Serial}" />
No need to get input values by hand. Simply let the framework synchronize the value.
How to use a local json model:
Create
initItemViewModel: function () {
return new JSONModel({
Serial: ""
});
}
this._oViewModel = this.initItemViewModel();
this.setModel(this._oViewModel, "TransportModel");
Using
this.getView().getModel("TransportModel").setProperty("/Serial", serial);
<Text text="{TransportModel>/Serial}" width="auto" maxLines="1"/>

Event Handler for JSONModel Change?

Say, there's an sap.m.table whose items are bound to a JSON model - "/rows". Outside sap.m.table layout, there's a toolbar that contains "Add" button to add rows to the table. "Add" button adds rows to the table using model's setProperty method. Now, the requirement is to disable "Add" button when JSON model "/rows" length has reached 10. How do we create a handler to observe the changes of JSON model's "/rows" property? https://sapui5.netweaver.ondemand.com/1.52.22/#/api/sap.ui.model.Model/events/propertyChange states that
Currently the event is only fired with reason sap.ui.model.ChangeReason.Binding which is fired when two way changes occur to a value of a property binding.
This means that the eventHandler of propertyChange doesn't get triggered when JSONModel's setProperty() is called. Is there a way out where we can observe the changes of JSONModel's property changes - in this case, "/rows" property of the JSONModel?
Well I can think of several ways to achieve this
1. Standard view binding + formatter:
View
...
<Button text="Add" press="onPressAdd" enabled="{path: '/rows', formatter: '.isAddEnabled'}" />
...
Controller:
Controller.prototype.isAddEnabled = function(rows) {
return rows && rows.length < 10;
}
2. Expression binding (pure xml)
...
<Button text="Add" press="onPressAdd" enabled="{= ${/rows/length} < 10 }" />
...
3. JSONPropertyBinding (pure javascript)
You can call bindProperty on JSONModel to create a property binding that can be observed for changes:
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.Model/methods/bindProperty
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.json.JSONPropertyBinding
Controller.prototype.onInit = function() {
var model = this.getMyJsonModel();
var button = this.getView().byId("myButtonId");
model.bindProperty("/rows").attachChange(function(event) {
button.setEnabled(event.getSource().getValue().length < 10);
})
}

Setting multiple properties of a component with one function

I have a component in a list in a sapui5 XML view and I want to set multiple properties of that component with one function. E.g. I want to set text, status, tooltip and icon of an ObjectStatus together, because the values of those are all different facets of the same data. The issue is that i have to calculate the values to set to those properties from the model with the same relatively time-heavy function. If I write a separate formatter for each of those properties, it has to run the same function for each property. Instead of this I would like to write one function that runs this time-heavy function once and sets a value to all those properties at the same time.
To accomplish this, I have tried creating a sapui5 fragment that could be placed in the list and filled with different information by the createContent function for each instance of that fragment. However I cannot figure out how to do this.
In the view definitions I'm trying to instantiate the fragment like this:
<core:Fragment fragmentName="QuantificationParameter" type="JS" path="{project>}"/>
And then I'm trying to set different content to each instance of the fragment:
sap.ui.jsfragment("namespace.fragments.QuantificationParameter", {
createContent: function(oParentController) {
//Get the object bound to this list item
var derived; //Calculate some intermediate information from this object
return new sap.m.ObjectStatus({
icon: derived.icon,
text: derived.text,
state: derived.state,
tooltip: derived.tooltip
});
}
});
While debugging it seems that the createContent function of the fragment is run only once and I cannot figure out any way to access the data that I'm trying to bind to the fragment. Is there any way I can render different content to each instance of the fragment?
What you are searching for is called databinding.
But first of all: we do not use JS Fragments, due to the same reason we do not use JS views. Here s a little Blog written on that topic.
https://blogs.sap.com/2018/05/01/why-do-we-use-xml-views-rather-js-views-in-sapui5/
Now the databinding part:
I asume, that Fragment will have the same controlls for each instance and you just want the values to change. To do just that you need to create a JSONModel either in your BaseController or component.js. In this Model you store i.e. your Labels text.
Inside your Fragmet you bind that property to the label. Since JSONModels bindingmode is two way by default the Label will change dynamically if you update the model. You can update the model i.e. everytime the user clicks on one of your list items.
Framgmet example:
<core:FragmentDefinition
xmlns="sap.m"
xmlns:f="sap.ui.layout.form"
xmlns:core="sap.ui.core">
<f:SimpleForm
editable="true">
<f:content>
<Input
value="{baseModel>/inputA}"
type="Text"
placeholder="{i18n>placeHolder}"/>
<TextArea
value="{baseModel>/textA}"/>
<TextArea
editable="false"
value="{baseModel>/textB}"/>
</f:content>
</f:SimpleForm>
</core:FragmentDefinition>
creation of the model i.e in component.js:
var oBaseModel = new JSONModel({
inputA: "",
textA: "",
textB: ""
});
this.setModel(oBaseModel, "baseModel");
example for your press lit item funtion:
(should be in the controller of the view your list is located in)
onListPress: function (oEvent) {
var oLine = oEvent.getSource().getBindingContext("yourRemoteService").getObject();
this._oBaseModel.setProperty("/inputA", oLine.ListPropertyA);
this._oBaseModel.setProperty("/textA", oLine.ListPropertyb);
this._oBaseModel.setProperty("/textB", oLine.ListPropertyC);
}
You should really give that tutorial a go:
https://sapui5.hana.ondemand.com/#/topic/e5310932a71f42daa41f3a6143efca9c

Group of combobox dynamically in ZK

I am totally new in ZK. I need to create N combobox with their labels dynamically and populate them. I already populate a combobox with its id, but as there can be many combobox I should not know their ids, so It does not solve my problem.
I need to add N combobox, their labels and populate them dynamically. Is there any way to create that group of combobox and set them dynamically? Any ideas?
The code bellow works to populate the combo already knowing its fixed id.
//In this example I assume I have a label and a combobox. But could have 0 to N of them.
private Label lblComboMetadatos;
private Combobox cmbMetadatos;
//THEN
if (cmbMetadatos.getItemCount() == 0) {
lblComboMetadatos.setValue(trdMetaTipoDocumental.getNombreMetadato()); //Here I set the name of label but I should really can not know how many of them could be. There may exist 0..N
for (TrdMetadato trdMetaDato: trdMetaTipoDocumental.getTrdMetadatos()) {
String enumValores = trdMetaDato.getValoresEnumerado(); //Here I set the values of a combobox but I can not know how many of them could be. There may exist 0..N
cmbMetadatos.appendItem(enumValores]);
}
}
<zk>
<window id="idWindow" title="nameWindow" apply="controller.java" border="normal" closable="true" sizable="true" maximizable="true" maximized="true" height="85%" width="150%" style="overflow:auto;">
<!-- CONTINUES -->
<groupbox>
<hlayout>
<label id="lblComboMetadatos" />
<combobox id="cmbMetadatos"></combobox>
</hlayout>
</groupbox>
<!-- CONTINUES -->
</window>
</zk>
This question is very similar to your last question. You should wire the parent container (hlayout in this case) to your controller and then create the components there.
#Wire
private Component container; // your hlayout
#Override // This method should be specified by a composer super class
public void doAfterCompose(Component comp) throws Exception
for (<count an index or loop over data>) {
hlayout.appendChild(new Label("Hello World");
Combobox cb = new Combobox();
// append Comboitems
cb.addEventListener(Events.ON_SELECT, ...);
hlayout.appendChild(cb);
}
}
If you used MVVM, you could use children binding to create the components in zul.