Swift UI TextField onCommit called when lost focus (macOS) - swift

I am having the following text field in content view:
func doCommit(){
print("\(self.status.textValue)")
}
var body : some View {
TextField("Your input:", text: self.$status.textValue, onCommit:{
self.doCommit()
}).lineLimit(1).focusable(true, onFocusChange: { focused in
print ("\(focused) changed")
})
...
}
When the text field got focus, and type return , the doCommit got called, which is what I want,
but when I click on something else, and then click the text field and click somewhere else, the doCommit got called again, and the focusable onFocusChange is not call.
I do not want the func been called when lost focus , but only when return/entry

It appears onFocusChange only gets called when you use the tab key to iterate through different UI elements, not when you click into and away from the TextField

Related

Passing keyboard events from NSTextView to another

I have NSTextView which pops up a NSPopOver that contains another NSTextView. In some cases, I'd like to pass the keyboard events (arrow keys, mostly) from the "top" text view to the bottom one.
I have overridden keyDown on the topmost text view and tried various ways of forwarding the keyboard event to the view below.
Just calling bottomTextView.keyDown(with: event) doesn't do anything. The closest I've gotten is using window.sendEvent(event).
override func keyDown(with event: NSEvent) {
if (NSLocationInRange(Int(event.keyCode), NSMakeRange(123, 4)) &&
self.string.count == 0 && event.modifierFlags.contains(.shift)) {
// Pass the event through somehow
return
}
super.keyDown(with: event)
}
Through trial and error, I found one way which actually did pass on the events: calling the methods twice.
// Make the bottom text field first responder
self.window?.makeFirstResponder(self.delegate.bottomTextView)
self.window?.makeFirstResponder(self.delegate.bottomTextView)
// Send the keydown event to window
self.window?.sendEvent(event)
self.window?.sendEvent(event)
However, this causes strange issues, such as the topmost text view getting a one-byte string as its contents.
Is there a correct way to actually forward any key events from a text view to another, or is it even possible?

How to access control from the popup fragment by ID

I want my text area to be empty after I press OK button.
I have try this line this.byId("id").setValue("")
onWorkInProgress: function (oEvent) {
if (!this._oOnWorkInProgressDialog) {
this._oOnWorkInProgressDialog = sap.ui.xmlfragment("WIPworklist", "com.sap.FinalAssestments.view.WorkInProgress", this);
//this.byId("WIP").value = "";
//this.byId("WIP").setValue();
this.getView().addDependent(this._oOnWorkInProgressDialog);
}
var bindingPath = oEvent.getSource().getBindingContext().getPath();
this._oOnWorkInProgressDialog.bindElement(bindingPath);
this._oOnWorkInProgressDialog.open();
},
//function when cancel button inside the fragments is triggered
onCancelApproval: function() {
this._oOnWorkInProgressDialog.close();
},
//function when approval button inside the fragments is triggered
onWIPApproval: function() {
this._oOnWorkInProgressDialog.close();
var message = this.getView().getModel("i18n").getResourceBundle().getText("wipSuccess");
MessageToast.show(message);
},
The text area will be in popup in the fragment. I am expecting the text area to be empty.
If you instantiate your fragment like this:
sap.ui.xmlfragment("WIPworklist", "com.sap.FinalAssestments.view.WorkInProgress", this);
You can access its controls like this:
Fragment.byId("WIPworklist", "WIP").setValue(""); // Fragment required from "sap/ui/core/Fragment"
Source: How to Access Elements from XML Fragment by ID
The better approach would be to use a view model. The model should have a property textAreaValue or something like that.
Then bind that property to your TextArea (<TextArea value="{view>/textAreaValue}" />). If you change the value using code (e.g. this.getView().getModel("view").setProperty("/textAreaValue", "")), it will automatically show the new value in your popup.
And it works both ways: if a user changes the text, it will be automatically updated in the view model, so you can access the new value using this.getView().getModel("view").getProperty("/textAreaValue");.
You almost have it, I think. Just put the
this.byId("WIP").setValue("") line after the if() block. Since you are adding the fragment as a dependent of your view, this.byId("WIP") will find the control with id "WIP" every time you open the WIP fragment and set its value to blank.
You are likely not achieving it now because A. it is not yet a dependent of your view and B. it is only getting fired on the first go-around.

Delete command is not working for NSTextField

I have a textfield to which I need to listen to tab key, so that when ever the user press tab from that text field I can move the focus to next text field. I have implemented the below code to perform that operation.
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if (commandSelector == #selector(insertTab)) {
if control == firstTextField {
makeNextTextFieldAsFirstResponder()
}
}
return true
}
My problem is that as I have implemented this code, delete key is not doing what it suppose to do(removing last character from the text field's text). Am I missing something here?
I am new to Mac development so excuse me if this question has been asked already somewhere.
I found the solution to my own problem. It turns out to be a simple mistake. I am not sure about how exactly this method works and how the return value affect the nature of the text field as I am new to Mac development, but it seems that the default return value should be false. Any insights to this behaviour are welcome.

Eureka PushRow on a modal, view won't close after item selection

I am using a SplitViewController and on the detail page (which is set to "defines context"), the user can select "+" in the navbar and I present the next view controller "modally over current context" using a segue. On that view controller I am using Eureka and one of the rows I want to use is PushRow. The issue I am running into is when I select an option on the PushRow, the view (table of options to choose that Eureka generated) never closes. The list of options stays full screen. I can see that PushRow.onChange is called and it has the correct value. For some reason that topmost view will not close.
I dug deeper and it seems like I need to modify the PushRow presentationMode to be "presentModally" since I am presenting it from a modal. However, I am not sure what to put for the controllerProvider. Is this the right path? If so, what would the correct syntax be? I also tried doing a reload in the onChange but that didn't make a difference.
private func getGroupPushRow() -> PushRow<String> {
return PushRow<String>() {
$0.title = "Group"
$0.selectorTitle = "What is the Group?"
$0.noValueDisplayText = "Select a Group..."
$0.options = self.getGroups()
$0.presentationMode = PresentationMode.presentModally(controllerProvider: ControllerProvider<VCType>, onDismiss: { () in
})
$0.onChange({ (row) in
print("in onchange \(row.value)")
// row.reload()
// self.tableView.reloadData()
})
}
}
I eventually figured out a solution so I'm posting it here to hopefully help out somebody else. Going off of the example above, replace presentationMode & onChange with this code. Note that if you are using another object in your PushRow besides String, then the type in PushSelectorCell should be that type instead.
$0.presentationMode = PresentationMode.presentModally(
controllerProvider: ControllerProvider.callback {
return SelectorViewController<SelectorRow<PushSelectorCell<String>>> { _ in }
},
onDismiss: { vc in
vc.dismiss(animated: true)
})
$0.onChange({ (row) in
row.reload()
})

How to highlight the selected tab in sap.m.IconTabBar?

Dear SAPUI5 developers,
I have a sap.m.IconTabBar and I set the active tab by the code when the user switch between pages. I used the following code:
sap.ui.getCore().byId(this.createId("iconTabBar")).setSelectedKey("1");
The problem is that it switch the selected tab correctly to the first tab. But it does not show the blue line under the tab that shows it is selected.
Please look at the following images:
What shows when I select the first tab by code:
But what it shows when I press the tab by the mouse it shows a blue line under the icon like the following:
As #Ash said in the comments you need to call fireSelect but this works just if user the second tab at first. If the user is on the first tab and switches between the pages then fireSelect does not act properly. Thus you need to select the second tab at first then it will works almost all times.
sap.ui.getCore().byId(this.createId("iconTabBar")).setSelectedKey("2");
sap.ui.getCore().byId(this.createId("iconTabBar")).setSelectedKey("1");
sap.ui.getCore().byId(this.createId("iconTabBar")).fireSelect();
Ok I had a look into the IconTabBar source Code and theres something I dont really get why but here is how it proceeds :
when you call IconTabBar.setSelectedKey(key), it calls IconTabHeader.setSelectedKey(key)
then internally the IconTabBarHeader calls setSelectedItem(item, true)
the 'true' here is important, the parameter is named 'bAPIchange' in the setSelectedItem function, and it is used as condition for the fireSelect() :
if (!bAPIchange) {
// fire event on iconTabBar
if (bIsParentIconTabBar) {
oParent.fireSelect({
selectedItem: this.oSelectedItem,
selectedKey: sSelectedKey,
item: this.oSelectedItem,
key: sSelectedKey
});
} else {
// fire event on header
this.fireSelect({
selectedItem: this.oSelectedItem,
selectedKey: sSelectedKey,
item: this.oSelectedItem,
key: sSelectedKey
});
}
}
Which explains why the event is not fired in your case