Adding TextEditingControllers in a loop in Flutter isn't working - dart

What I try to achieve is for the TextInputField to be autovalidated once there is more than 1 character entered.
Here's my initState (simplified):
#override
void initState() {
autoValidateList.addAll([
_autoValidateEmail,
_autoValidateCompanyName,
_autoValidatePhoneNo,
_autoValidateName,
_autoValidateSurname
]);
textEditingControllersList.addAll([
_emailController,
_companyNameController,
_phoneNoController,
_nameController,
_surnameController
]);
for (int i = 0; i < textEditingControllersList.length; i++) {
TextEditingController controller = textEditingControllersList[i];
controller.addListener(() => () {
print(
'Listener entered. companyName? ${controller == _companyNameController}');
if (controller.text.length > 0) {
print('=> true');
setState(() => autoValidateList[i] = true);
} else {
print('=> false');
setState(() => autoValidateList[i] = false);
}
});
}
_emailController.text = widget.loginData.email;
super.initState();
}
If I add the listeners not in a loop, for example:
_emailController.addListener(() => setState(() {
if (_emailController.text.length > 0) {
_autoValidateEmail = true;
} else {
_autoValidateEmail = false;
}
}));
It works fine.
None of the print statements get executed. What am I missing here?

There's a very insidious error here. Notice that in your addListener, you're passing a function that returns a function. What you want to execute is the function that is being returned, but you're actually executing the function that you're passing.
In a more clear syntax, you're doing this:
controller.addListener(() {
return () {
// Your code
};
});
So, what is happening is:
controller.addListener(() {
print('This is going to be executed');
return () {
print('This is NOT going to be executed. Your code used to be here.');
};
});
Instead of:
controller.addListener(() => () {
...
});
You should be doing:
controller.addListener(() {
...
});
Also, this is not related, but you should be calling super at the beginning of initState, not at the end.

Related

How to send a result to sender via contextBridge / IPCRenderer?

I have a electron that looks like this
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
electronStore: {
get(val) {
ipcRenderer.send('electron-store-get', val);
},
set(property, val) {
ipcRenderer.send('electron-store-set', property, val);
},
// Other method you want to add like has(), reset(), etc.
},
});
and ipcMain that looks like this
ipcMain.on('electron-store-get', async (event, val) => {
store.get(val);
// console.log(reply);
// return reply;
// event.reply('electron-store-get', reply);
});
ipcMain.on('electron-store-set', async (event, property, val) => {
// console.log(val);
store.set(property, val);
});
When I was trying to call the function via electron.electronStore.get(), it returns undefined
let a = window.electron.electronStore.get('test');
console.log(a);
However, I've tested that on the line of ipcRenderer.send(""), I was able to receive data by setting as below
let result = ipcRenderer.send('electron-store-get',val);
console.log(result);
Which mean, ipcRenderer is not undefined and set has been successfuly, get as-well, just it went missing when i invoke the ipcMain Get functions
Your current preload API isn't actually returning anything:
get(val) {
ipcRenderer.send('electron-store-get', val);
}
You'll want to either use the synchronous API: return ipcRenderer.sendSync('electron-store-get', val) and then have your handler in main do:
ipcMain.on('electron-store-get', (event, val) => {
event.returnValue = store.get(val);
});
Or make the preload API async:
get(val) {
return ipcRenderer.invoke('electron-store-get', val);
}
ipcMain.handle('electron-store-get', (event, val) => {
return store.get(val);
});
And then:
let a = await window.electron.electronStore.get('test');

Rxjs BehaviorSubject error handling when used with mergemap

I have the following code
#Injectable()
export class ReceptionService {
private generalInfoDataSrc$ = new BehaviorSubject<any>(null);
public generalInfoData = this.generalInfoDataSrc$.asObservable();
setGeneralInfo(dataSrc: GeneralInfoMModal) {
this.generalInfoDataSrc$.next(dataSrc);
}
}
From my component1 I will set the above as
OnSelect(patient: any) {
let generalInfo = new GeneralInfoMModal();
generalInfo.id = patient.id;
// some other code here
// this.recepService.setGeneralInfo(generalInfo);
}
// from component2
//
ngOnInit() { getPatientDetails() }
getPatientDetails() {
this.receptionService.generalInfoData.pipe(mergeMap(response => {
if (response && response.id) {
this.loading = true;
return this.receptionService.get('User/Get' + response.id, this.sourceobj);
} else {
return of(null);
}
}), takeUntil(this.unsubscribe$)).subscribe(response => {
this.patient = response;
this.loading = false;
}, error => {
this.loading = false;
// this.utility.showMsg('An error occurred while getting user.')
}, () => {
})
}
Every things works well. I keep on selecting a user thereby calling the User/Get api. But if in case if the api returns an error then error part is executed after which when there is a change in behaviorsubject(user is selected) it doesn't call the User/Get. Is there other way of handling errors with behaviorsubject or any other approach to handle the idea. How a behaviorsubject should be used in such a case.
If you are using the same behavior subject over and over again, and if there is an error, you need to set the behavior subject back to null, so that when the next user is set, it will get the latest value.
Try something like this:
getPatientDetails() {
this.receptionService.generalInfoData.pipe(mergeMap(response => {
if (response && response.id) {
this.loading = true;
return this.receptionService.get('User/Get' + response.id, this.sourceobj);
} else {
return of(null);
}
}), takeUntil(this.unsubscribe$)).subscribe(response => {
this.patient = response;
this.loading = false;
}, error => {
this.loading = false;
///////////////////////////////// ADD THIS LINE ///////////////////////
this.recepService.setGeneralInfo(null);
// this.utility.showMsg('An error occurred while getting user.')
}, () => {
})

Unable to access Work Item Tracking services Azure DevOps Extensions

I am rendering extension on the Work item page using
<WebpageControlOptions AllowScript="true" ReloadOnParamChange="true">
<Link UrlRoot="http://.../extension/Validate-extension/1.0.69/assetbyname/workItemNotifications.html"/>
</WebpageControlOptions>
Following is the html/js code:
var workItemID = 0;
VSS.init({
explicitNotifyLoaded: true,
usePlatformScripts: true
});
VSS.ready(function () {
var currentContext = VSS.getWebContext();
VSS.register(VSS.getContribution().id, function (context) {
return {
// event handlers, called when the active work item is loaded/unloaded/modified/saved
onFieldChanged: function (args) {
if (!changedFields[args.id]) {
changedFields[args.id] = [];
changedFieldCount[args.id] = 0;
}
$.each(args.changedFields, function (key, value) {
if (!changedFields[args.id][key]) {
changedFields[args.id][key] = value;
changedFieldCount[args.id]++;
}
});
},
onLoaded: function (args) {
console.log("OnloadNotification");
VSS.require(["TFS/WorkItemTracking/Services"], function (workItemServices) {
workItemServices.WorkItemFormService.getService().then(function (workItemFormSvc) {
if (workItemFormSvc.hasActiveWorkItem()) {
console.log("Active work item is available.");
workItemFormSvc.getFieldValues(["System.Id"]).then(
function (value) {
var val = JSON.stringify(value);
$.each(value, function (key, values) {
if(key == "System.Id"){
workItemID = values;
}
});
});
}
else {
console.log("Active work item is NOT available.");
}
});
});
},
onUnloaded: function (args) {
},
onSaved: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onReset: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onRefreshed: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
}
};
});
VSS.notifyLoadSucceeded();
});
$(document).ready(function () {
$("#btnValidate").click(function () {
var getResponse = ValidateUser();
VSS.require(["TFS/WorkItemTracking/Services"], function (_WorkItemServices) {
var wiServiceNew = _WorkItemServices.WorkItemFormService.getService();
wiServiceNew.setFieldValue("System.Title", "Title set from your group extension!");
});
});
});
2 things which I am trying to achieve
After button click event to validate user, I have to access the Work Item fields after successful validation. Unable to access _WorkItemServices.
Not able to to get the Work Item fields.
When I set workItemID variable OnLoad event, it resets to 0 when a tab is clicked, value is not getting retained which is set OnLoad.
You may try to interact with the IWorkItemFormService service. For example:
import {
IWorkItemChangedArgs,
IWorkItemFieldChangedArgs,
IWorkItemFormService,
IWorkItemLoadedArgs,
WorkItemTrackingServiceIds
} from "azure-devops-extension-api/WorkItemTracking";
Check the sample here:
https://github.com/microsoft/azure-devops-extension-sample/blob/master/src/Samples/WorkItemFormGroup/WorkItemFormGroup.tsx

How to setState() of a text field after handling an error in Flutter?

I have a function called LoginWithFb(). The function has a try catch block:
void loginWithFb() async {
try {
var auth = AuthProvider.of(context).auth;
print('Signing up with fb...');
setState(() {
_showProgressIndicator = true;
});
FirebaseUser user = await auth.signInWithFBAcc();
uId = user?.uid;
if (uId != null) {
print('Signed in: $uId');
widget.onSignedIn(user);
} else {
print('fb login cancelled');
}
// _showAlert(context);
setState(() {
_showProgressIndicator = false;
});
} catch (exception) {
print(exception.toString());
setState(() {
_showProgressIndicator = false;
});
}
When the error is caught, I want to display message to the user. The message has to be in a text field and not via a dialog. At the moment I have an empty Text('') widget in my build method. I want to write text to the text widget when the error is caught..
Just use local variable for storing message and show it via Text widget
String message = "";
void loginWithFb() async {
try {
...
} catch (exception) {
print(exception.toString());
setState(() {
message = "Some error happens";
_showProgressIndicator = false;
});
}
In widget:
Text(message);

Why is this callback being shown as null in this dart method

So I have this code in my flutter app - here the function refreshState is being called by the method foo which is passing in a lambda.However during debugging it says the callback is null. Any ideas why this is happening because of this my callback code is not being executed.
void refreshState(Function callback)
{
if(isAlive) {
setState(() {
if (callback != null) {
callback;
}
});
}
}
at one point in my code I am doing this
void didPush() {
foo();
}
void foo()
{
refreshState(() { //<------------------This lambda is showing up as null in the paramter of refreshState
isBusy = true;
});
}
Any ideas of why this lamda is showing up as null in the refreshState function parameter ?
You misunderstand the debug view here. It is a function () returning (=>) null. You just do not execute it.
() => ...
This is just a shortcut for:
() {
return ...
}
To execute your callback you need to add parantheses though. That would be:
setState(() {
if (callback != null)
callback();
});

Resources