how to pass data from view to controller in SAPUI5 - sapui5

I have a view in my sapui5 app, where on a button press I want to pass some data to the controller, to the function invoked on the press event.
Below is the code snippet :
<HBox justifyContent="SpaceAround" alignItems="Center" >
<Input type="Tel" pattern="[0-9]*" inputmode="numeric"
value="{path:'cart>Quantity/value',
type: 'sap.ui.model.type.Integer'}"
class="qtyInput" editable="{cart>Quantity/isEditable}"/>
<core:Icon src="sap-icon://delete" press="deleteItem" visible="{cart>isDeletable}"/>
</HBox>
Here, I need to pass "{cart>lineNumber}" and ”{cart>itemKey}" to the function “deleteItem” which is there in the controller.
Please suggest.

You can try using sapui5 CustomData to pass your custom data on a event.
For that, you need to add below namespace in your view:
xmlns:app="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1"
and add app:propertyName=“value” inside the Icon element.
Please take a look at below example, I updated your code with the changes required:
<core:Icon src="sap-icon://delete" press="deleteItem" visible="{cart>isDeletable}" app:lineNumber="{cart>lineNumber}" app:itemKey="{cart>itemKey}"/>
Thanks.

Another way to resolve this problem is, if you are getting the data from the same model on which the list is being iterated, you may get the index number of the list item and then read the specific record from the model itself using the index number.
Let me know if you need a code example for this.

Related

Forms in reactjs with flux

I have a form, this form needs to post some data to my backend. With flux, what is the best practice for doing this, use a store?
My issue with using a store is that I have a sub component inside of my form that allows me to select a number 1-5 with buttons. I wanted that component to be reusable, but if i use a store, I have to hard code the store into the child component which means I cant really use it elsewhere. Instead do I just set the parent state from the child?
If anyone can point out some good tutorials or examples of react/flux forms let me know.
In my opinion any back end interaction should be done by using actions, but...
if you want to use store anyway then you can create additional attribute (prop) in your sub-component which will be a function (f.e. onChange) which should be passed from parent component as prop (this function should set data in store). Then you can reuse this component, because only parent needs to have access to store.
So in subcomponent:
onButtonClick(e) {
this.state.value = e.target.value;
if (this.props.onChange) this.props.onChange(e.target.value);
}
<div>
<button onClick={this.onButtonClick.bind(this)} value="1">1</button>
<button onClick={this.onButtonClick.bind(this)} value="2">2</button>
<button onClick={this.onButtonClick.bind(this)} value="3">3</button>
<button onClick={this.onButtonClick.bind(this)} value="4">4</button>
<button onClick={this.onButtonClick.bind(this)} value="5">5</button>
</div>
and in parent:
setMyStoreState(value) {
store.setNumber(value);
}
<Subcomponent onChange={this.setStoreState.bind(this)} />
or something like this.
Code not tested, but you should get the idea.

BindElement() on form in popup dialog / fragment

Following on from my question about Is it possible to use 2 models in one view I am now confused about how to apply bindElement on a form in an XML fragment.
The fragment (cut down for brevity):
<core:FragmentDefinition
namespaces here...>
<Dialog id="theDialogId" title="Edit Subdetail">
<content>
<f:SimpleForm id="EditFormId" editable="true" >
<f:content>
<Label id="lblName" text="Name" labelFor="inpName" />
<Input id="inpName" editable="true" value="{name}"/>
</f:content>
</f:SimpleForm>
</content>
</Dialog>
</core:FragmentDefinition>
The challenge: Assume I have a model containing path /master/0/detail/6/subdetail/2 - how to bind the simpleform to this path? Im the examples I have seen, elements in dialogs are given a value by
sap.ui.getCore().byId("inputId").setValue("some value)
and accessed via
var uid = sap.ui.getCore().byId("inputId").getValue()
However I want to employ binding to the path.
The issue I have is how to get a reference to the simpleform so that I can use bindElement().
If this were a view I would use
var theForm = this.getView().byId("EditFormId");
var oBindingContext = event.oSource.getBindingContext();
theForm.bindElement(oBindingContext.getPath())
However fragments are not tightly coupled to the view so this will not work. Instead I believe I have to use
var dlgForm = sap.ui.core.Fragment.byId("theFragmentId", "EditFormId")
var oBindingContext = event.oSource.getBindingContext();
dlgForm.bindElement(oBindingContext.getPath())
This may well be correct but I am at a loss as to how to apply the "theFragmentId" in the XML view declaration. Can anyone clear the fog for me?
EDIT: What I was missing, as per the accepted answer, is that the desired fragment ID can be given as the first (optional) parameter of the sap.ui.xmlfragment() function. The key to binding into a fragment-based control is to get a handle to it but the sap.ui.core.Fragment.byId(fragId, ctrlId) function requires a fragment id. My issue was that I was fixated on the XML fragment declaration and how to apply an id there. This feels inconsistent within SAPUI5 but I guess being able to apply an ID to the fragment has some amenity somewhere, maybe.
You can try something like this...
onOpenDialog: function(oEvent) {
if(!this._oEditSubDetailDialog){
this._oEditSubDetailDialog = sap.ui.xmlfragment("fragmentId", "namespace.and.path.to.your.fragment", this);
this.getView().addDependent(this._oEditSubDetailDialog);
}
var sPathToBind = oEvent.getSource().getBindingContext().getPath();
sap.ui.core.Fragment.byId("fragmentId","EditFormId").bindElement(sPathToBind);
this._oEditSubDetailDialog.open();
}
...just need to make sure that the source control of the event has the context bound to it that you want to edit.
You could also bindElement directly on the dialog, this way you would not need to retrieve the form control within the dialog...
this._oEditSubDetailDialog.bindElement(sPathToBind)
This API documentation and this walkthrough guide regarding XML fragments may be useful

how to reach components in macrocomponent by id?

I have a zul file (MainPage.zul) which contains a macrocomponent (configtabs). Macrocomponent's zul file inturn contains another macrocomponent(fieldListBox). How can I use the id of second macrocomponent(fieldListBox) in my MainPage's Controller class? I want to set model for second macrocomponent in doAfterCompose method of MainPage's cOntroller class.
Example code:
<?component name="configtabs" macro-uri="iam.configtab.zul" ?>
<zk>
<window>
<configtabs />
</window>
</zk>
configtab.zul
<hbox>
<fieldListBox id="fieldsbox" />
</hbox>
You can use zk selectors for that.
Click here for a little bit of explanation of what are those selectors.
Also every component has query methods. If you use those methods with the selectors you can query for components inside other components. It's been very useful to me.
For example on your doAfterCompose you can do:
configtabs.queryAll("fieldListBox")
Or
configtabs.queryAll("#fieldsbox")
And it returns the component or components that you want to set model.
I hope it's helpful. It depends on the context.

How to get the filename of a filepicker.io picture to appear in the input field next to it

I am trying to get the filename of an uploaded picture to appear in the input field next to the picker button (for filepicker.io) . Basically I am trying to find what to put in the value field for the input tag to get the filename to appear once the picture is uploaded. Here is the code I have:
<div class="row margin" id='img-row'>
<input id="filename" disabled="disabled" value="<WHAT DO I PUT HERE?>" class="input" type="text" style="width: 360px;"/>
<input name="img" data-fp-class="form-simple-action-btn filepicker_launcher" data-fp-button-text="Choose Image" data-fp-services="COMPUTER,FACEBOOK,FLICKR,INSTAGRAM,PICASA" data-fp-container="modal" data-fp-mimetypes="image/*" type="filepicker" data-fp-apikey="#################" id='campaign-img-input' value="<php echo h($_POST['img'])"/>
</div>
Thank you for your help! I haven't found any other examples like this in the documentation.
The recommended way to do this would be to bind a function to the onchange event of the filepicker input type. Once the upload occurs, the function will be called, and you can pull the filename out of the e.fpfile attribute.
Alternatively, it may be easier to use the filepicker.pick call directly given that you are interested in customizing the behavior. The widget is great for a drop-in solution in many cases, but if you're looking to customize further I'd recommend using the javascript api directly.

Listening to click event on ListView

Feels like I'm missing something stupid here, but what's the recommended method to listen to the click event on a listview?
At the moment I've got:
WinJS.Utilities.query(".menuHolder").listen("click", linkClickHandler, false);
And my listview template uses the class 'menuHolder' for it's items:
<div id="menuTemplate"
data-win-control="WinJS.Binding.Template">
<div class="menuHolder">
<!-- menu img -->
<img src="#" data-win-bind="src : pic; alt : title" />
<div class="menuText">
<!-- menu text -->
<h1 data-win-bind="innerText : title"></h1>
<!-- menu desc -->
<h4 data-win-bind="innerText : description"></h4>
</div>
</div>
</div>
I don't seem to hit my breakpoint, in my link handler, or invoke it's function. Any thoughts?
EDIT:
As a follow on question (bearing in mind the item invoked event) is anyone aware of the recommended approach to pass data between a listview and the iteminvoked event, if I say wanted to use the WinJS.Navigator class to move around an application? I'm guessing I need to cast some part of the eventInfo into a suitable object and retrieve information, what part?
Assuming the data you want to "pass" is the data that is bound to the item that was invoked, you can do that in the event arguments that are passed in to the iteminvoked event. One of mine looks like this...
demosLV.oniteminvoked = function(e) {
e.detail.itemPromise.then(function(item) {
var location = format("/pages/{0}/{0}.html", item.data.key);
WinJS.Navigation.navigate(location, item.data);
});
};
So the demosLV is the ListView. I'm setting the oniteminvoked to a function. That function receives "e" as the event args. In the function I access e.detail.itemPromise and hang a .then off of it. Then I access the actual data in the .then using item.data.
Hope that's what you meant. BTW, the format function is one of mine in case you're wondering why it doesn't work for you.
Seems I was being a sausage, I needed to listen for the 'iteminvoked' event on the parent listview id reference, not the child level.
WinJS.Utilities.query("#menu").listen("iteminvoked", linkClickHandler, false);