flutter snackbar display based on stream
I currently have an interesting issue related to displaying of a snackbar based on a user action.
Above sounds very trivial, but lets elaborate:
I have 2 screens:
- list of employees
- Add employee
The application uses the bloc pattern (with streams/rxdart).
Here is what I want:
- User clicks on add employee FAB button in list of employees screen and is navigated to the Add Employee screen (works perfectly fine)
- User fills in employee details and clicks save
- Upon save, employee is added to the stream, and updated the list of employees screen (works fine)
- User is navigated BACK to list of employees (works fine)
- Snackbar is displayed stating that the employee has successfully been added (This is the problem)
I tried several ways of implementing this:
Add a new stream (employeeAdded), and when adding an employee to the employees stream, additionally push a boolean to employee added.
In the list of employees, add a new stream builder and in the builder logic add the snackbar.
This gives all sorts of problems, for example trying to display the snackbar before the page has been (re)build, and so on.
The question is twofold: What is good UX practice for this scenario, and what would be a good solution for this problem?
(will post code on request)
Thanks for the help!
flutter rxdart
add a comment |
I currently have an interesting issue related to displaying of a snackbar based on a user action.
Above sounds very trivial, but lets elaborate:
I have 2 screens:
- list of employees
- Add employee
The application uses the bloc pattern (with streams/rxdart).
Here is what I want:
- User clicks on add employee FAB button in list of employees screen and is navigated to the Add Employee screen (works perfectly fine)
- User fills in employee details and clicks save
- Upon save, employee is added to the stream, and updated the list of employees screen (works fine)
- User is navigated BACK to list of employees (works fine)
- Snackbar is displayed stating that the employee has successfully been added (This is the problem)
I tried several ways of implementing this:
Add a new stream (employeeAdded), and when adding an employee to the employees stream, additionally push a boolean to employee added.
In the list of employees, add a new stream builder and in the builder logic add the snackbar.
This gives all sorts of problems, for example trying to display the snackbar before the page has been (re)build, and so on.
The question is twofold: What is good UX practice for this scenario, and what would be a good solution for this problem?
(will post code on request)
Thanks for the help!
flutter rxdart
add a comment |
I currently have an interesting issue related to displaying of a snackbar based on a user action.
Above sounds very trivial, but lets elaborate:
I have 2 screens:
- list of employees
- Add employee
The application uses the bloc pattern (with streams/rxdart).
Here is what I want:
- User clicks on add employee FAB button in list of employees screen and is navigated to the Add Employee screen (works perfectly fine)
- User fills in employee details and clicks save
- Upon save, employee is added to the stream, and updated the list of employees screen (works fine)
- User is navigated BACK to list of employees (works fine)
- Snackbar is displayed stating that the employee has successfully been added (This is the problem)
I tried several ways of implementing this:
Add a new stream (employeeAdded), and when adding an employee to the employees stream, additionally push a boolean to employee added.
In the list of employees, add a new stream builder and in the builder logic add the snackbar.
This gives all sorts of problems, for example trying to display the snackbar before the page has been (re)build, and so on.
The question is twofold: What is good UX practice for this scenario, and what would be a good solution for this problem?
(will post code on request)
Thanks for the help!
flutter rxdart
I currently have an interesting issue related to displaying of a snackbar based on a user action.
Above sounds very trivial, but lets elaborate:
I have 2 screens:
- list of employees
- Add employee
The application uses the bloc pattern (with streams/rxdart).
Here is what I want:
- User clicks on add employee FAB button in list of employees screen and is navigated to the Add Employee screen (works perfectly fine)
- User fills in employee details and clicks save
- Upon save, employee is added to the stream, and updated the list of employees screen (works fine)
- User is navigated BACK to list of employees (works fine)
- Snackbar is displayed stating that the employee has successfully been added (This is the problem)
I tried several ways of implementing this:
Add a new stream (employeeAdded), and when adding an employee to the employees stream, additionally push a boolean to employee added.
In the list of employees, add a new stream builder and in the builder logic add the snackbar.
This gives all sorts of problems, for example trying to display the snackbar before the page has been (re)build, and so on.
The question is twofold: What is good UX practice for this scenario, and what would be a good solution for this problem?
(will post code on request)
Thanks for the help!
flutter rxdart
flutter rxdart
asked Jan 3 at 13:25
Joey RoosingJoey Roosing
1,43231936
1,43231936
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
@joey I have found a solution but I'm not sure that it's the best. I'm changing my app to bloc pattern now so I found the same problem as you so I did this:
On my bloc file y put a controller only for the scaffoldState:
ScaffoldState scaffold;
StreamController<ScaffoldState> _scaffoldController = StreamController<ScaffoldState>();
StreamSink<ScaffoldState> get setScaffold => _scaffoldController.sink;
And on the constructor of the bloc file y listen for that stream:
LoginBloc(){
_scaffoldController.stream.listen((sc){ scaffold = sc;});
}
On the widget I sink the scaffoldState whenever I want to use it:
onPressed:() {
bloc.setScaffold.add(Scaffold.of(context));
}
so then, I can show snackbars as usuall from the bloc:
scaffold.showSnackBar(SnackBar(content: Text(hi world'),),);
2
Oh, an interesting approach. The only problem I have with this is you are kind of mixing UI logic with your bloc. If you want to reuse your business logic in for example an angular app, this bloc will give errors because ScaffoldState doesn't exist. I do like the idea though, thanks for the insight!
– Joey Roosing
Jan 9 at 11:06
add a comment |
Although its not my favourite answer, I am also not sure if there is a better alternative; this is what I did as a temporary fix for future watchers:
Create a new stream (in my case employeeAdded), upon adding employees, also create an entry into the stream:
final _employees = BehaviorSubject<List<Employee>>(seedValue: List<Employee>());
final _employeeAdded = BehaviorSubject();
// streams (out)
Observable<List<Employee>> get employees => _employees.stream;
Observable<dynamic> get employeesAdded => _employeeAdded.stream;
addEmployee(Employee employee) async {
final newList = <Employee>..addAll(_employees.value)..add(employee);
await _employeeRepo.upsertEmployee(employee);
_employees.add(newList);
_employeeAdded.add(true);
//FIXME: Save to db
}
Note there is no seedValue in employeeAdded, this is to prevent the snackbar from showing on initial load.
In my screen / page I have a scaffold; it's body calls another method which should explain the rest of the code:
Widget _buildBody(EmployeeBloc bloc) {
return StreamBuilder(
stream: bloc.employees,
builder: (context, snapshot) {
if (!snapshot.hasData) {
bloc.employeesAdded.listen(
(_) => Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
),
),
);
bloc.seedEmployees();
return Center(
child: Text("No employees"),
);
}
return _buildList(bloc, snapshot.data);
},
);
}
Note the listen on the bloc with the hasData if.
This works for now, but would like to know if there is a more neat example.
can cause issues (memory leak?) because everytime !hasData passes, a new listener is added
– Joey Roosing
Jan 7 at 10:56
add a comment |
Wrap your body
(the child of your Scaffold
, in your case returned by _buildBody
) with a Builder
so you get to write some "free" code with the context
.
Now you can listen to the stream with a handler you provide (like you already did), but this time you register the listener only once per Scaffold
build (and not registering a listener at each event occurred in employeesAdded
stream).
@override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
bloc.employeesAdded.listen(
(_) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
), // SnackBar
);
},
);
return _buildBody(bloc);
},
), // Builder
); // Scaffold
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54023203%2fflutter-snackbar-display-based-on-stream%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
@joey I have found a solution but I'm not sure that it's the best. I'm changing my app to bloc pattern now so I found the same problem as you so I did this:
On my bloc file y put a controller only for the scaffoldState:
ScaffoldState scaffold;
StreamController<ScaffoldState> _scaffoldController = StreamController<ScaffoldState>();
StreamSink<ScaffoldState> get setScaffold => _scaffoldController.sink;
And on the constructor of the bloc file y listen for that stream:
LoginBloc(){
_scaffoldController.stream.listen((sc){ scaffold = sc;});
}
On the widget I sink the scaffoldState whenever I want to use it:
onPressed:() {
bloc.setScaffold.add(Scaffold.of(context));
}
so then, I can show snackbars as usuall from the bloc:
scaffold.showSnackBar(SnackBar(content: Text(hi world'),),);
2
Oh, an interesting approach. The only problem I have with this is you are kind of mixing UI logic with your bloc. If you want to reuse your business logic in for example an angular app, this bloc will give errors because ScaffoldState doesn't exist. I do like the idea though, thanks for the insight!
– Joey Roosing
Jan 9 at 11:06
add a comment |
@joey I have found a solution but I'm not sure that it's the best. I'm changing my app to bloc pattern now so I found the same problem as you so I did this:
On my bloc file y put a controller only for the scaffoldState:
ScaffoldState scaffold;
StreamController<ScaffoldState> _scaffoldController = StreamController<ScaffoldState>();
StreamSink<ScaffoldState> get setScaffold => _scaffoldController.sink;
And on the constructor of the bloc file y listen for that stream:
LoginBloc(){
_scaffoldController.stream.listen((sc){ scaffold = sc;});
}
On the widget I sink the scaffoldState whenever I want to use it:
onPressed:() {
bloc.setScaffold.add(Scaffold.of(context));
}
so then, I can show snackbars as usuall from the bloc:
scaffold.showSnackBar(SnackBar(content: Text(hi world'),),);
2
Oh, an interesting approach. The only problem I have with this is you are kind of mixing UI logic with your bloc. If you want to reuse your business logic in for example an angular app, this bloc will give errors because ScaffoldState doesn't exist. I do like the idea though, thanks for the insight!
– Joey Roosing
Jan 9 at 11:06
add a comment |
@joey I have found a solution but I'm not sure that it's the best. I'm changing my app to bloc pattern now so I found the same problem as you so I did this:
On my bloc file y put a controller only for the scaffoldState:
ScaffoldState scaffold;
StreamController<ScaffoldState> _scaffoldController = StreamController<ScaffoldState>();
StreamSink<ScaffoldState> get setScaffold => _scaffoldController.sink;
And on the constructor of the bloc file y listen for that stream:
LoginBloc(){
_scaffoldController.stream.listen((sc){ scaffold = sc;});
}
On the widget I sink the scaffoldState whenever I want to use it:
onPressed:() {
bloc.setScaffold.add(Scaffold.of(context));
}
so then, I can show snackbars as usuall from the bloc:
scaffold.showSnackBar(SnackBar(content: Text(hi world'),),);
@joey I have found a solution but I'm not sure that it's the best. I'm changing my app to bloc pattern now so I found the same problem as you so I did this:
On my bloc file y put a controller only for the scaffoldState:
ScaffoldState scaffold;
StreamController<ScaffoldState> _scaffoldController = StreamController<ScaffoldState>();
StreamSink<ScaffoldState> get setScaffold => _scaffoldController.sink;
And on the constructor of the bloc file y listen for that stream:
LoginBloc(){
_scaffoldController.stream.listen((sc){ scaffold = sc;});
}
On the widget I sink the scaffoldState whenever I want to use it:
onPressed:() {
bloc.setScaffold.add(Scaffold.of(context));
}
so then, I can show snackbars as usuall from the bloc:
scaffold.showSnackBar(SnackBar(content: Text(hi world'),),);
answered Jan 9 at 9:26
Jose JetJose Jet
916
916
2
Oh, an interesting approach. The only problem I have with this is you are kind of mixing UI logic with your bloc. If you want to reuse your business logic in for example an angular app, this bloc will give errors because ScaffoldState doesn't exist. I do like the idea though, thanks for the insight!
– Joey Roosing
Jan 9 at 11:06
add a comment |
2
Oh, an interesting approach. The only problem I have with this is you are kind of mixing UI logic with your bloc. If you want to reuse your business logic in for example an angular app, this bloc will give errors because ScaffoldState doesn't exist. I do like the idea though, thanks for the insight!
– Joey Roosing
Jan 9 at 11:06
2
2
Oh, an interesting approach. The only problem I have with this is you are kind of mixing UI logic with your bloc. If you want to reuse your business logic in for example an angular app, this bloc will give errors because ScaffoldState doesn't exist. I do like the idea though, thanks for the insight!
– Joey Roosing
Jan 9 at 11:06
Oh, an interesting approach. The only problem I have with this is you are kind of mixing UI logic with your bloc. If you want to reuse your business logic in for example an angular app, this bloc will give errors because ScaffoldState doesn't exist. I do like the idea though, thanks for the insight!
– Joey Roosing
Jan 9 at 11:06
add a comment |
Although its not my favourite answer, I am also not sure if there is a better alternative; this is what I did as a temporary fix for future watchers:
Create a new stream (in my case employeeAdded), upon adding employees, also create an entry into the stream:
final _employees = BehaviorSubject<List<Employee>>(seedValue: List<Employee>());
final _employeeAdded = BehaviorSubject();
// streams (out)
Observable<List<Employee>> get employees => _employees.stream;
Observable<dynamic> get employeesAdded => _employeeAdded.stream;
addEmployee(Employee employee) async {
final newList = <Employee>..addAll(_employees.value)..add(employee);
await _employeeRepo.upsertEmployee(employee);
_employees.add(newList);
_employeeAdded.add(true);
//FIXME: Save to db
}
Note there is no seedValue in employeeAdded, this is to prevent the snackbar from showing on initial load.
In my screen / page I have a scaffold; it's body calls another method which should explain the rest of the code:
Widget _buildBody(EmployeeBloc bloc) {
return StreamBuilder(
stream: bloc.employees,
builder: (context, snapshot) {
if (!snapshot.hasData) {
bloc.employeesAdded.listen(
(_) => Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
),
),
);
bloc.seedEmployees();
return Center(
child: Text("No employees"),
);
}
return _buildList(bloc, snapshot.data);
},
);
}
Note the listen on the bloc with the hasData if.
This works for now, but would like to know if there is a more neat example.
can cause issues (memory leak?) because everytime !hasData passes, a new listener is added
– Joey Roosing
Jan 7 at 10:56
add a comment |
Although its not my favourite answer, I am also not sure if there is a better alternative; this is what I did as a temporary fix for future watchers:
Create a new stream (in my case employeeAdded), upon adding employees, also create an entry into the stream:
final _employees = BehaviorSubject<List<Employee>>(seedValue: List<Employee>());
final _employeeAdded = BehaviorSubject();
// streams (out)
Observable<List<Employee>> get employees => _employees.stream;
Observable<dynamic> get employeesAdded => _employeeAdded.stream;
addEmployee(Employee employee) async {
final newList = <Employee>..addAll(_employees.value)..add(employee);
await _employeeRepo.upsertEmployee(employee);
_employees.add(newList);
_employeeAdded.add(true);
//FIXME: Save to db
}
Note there is no seedValue in employeeAdded, this is to prevent the snackbar from showing on initial load.
In my screen / page I have a scaffold; it's body calls another method which should explain the rest of the code:
Widget _buildBody(EmployeeBloc bloc) {
return StreamBuilder(
stream: bloc.employees,
builder: (context, snapshot) {
if (!snapshot.hasData) {
bloc.employeesAdded.listen(
(_) => Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
),
),
);
bloc.seedEmployees();
return Center(
child: Text("No employees"),
);
}
return _buildList(bloc, snapshot.data);
},
);
}
Note the listen on the bloc with the hasData if.
This works for now, but would like to know if there is a more neat example.
can cause issues (memory leak?) because everytime !hasData passes, a new listener is added
– Joey Roosing
Jan 7 at 10:56
add a comment |
Although its not my favourite answer, I am also not sure if there is a better alternative; this is what I did as a temporary fix for future watchers:
Create a new stream (in my case employeeAdded), upon adding employees, also create an entry into the stream:
final _employees = BehaviorSubject<List<Employee>>(seedValue: List<Employee>());
final _employeeAdded = BehaviorSubject();
// streams (out)
Observable<List<Employee>> get employees => _employees.stream;
Observable<dynamic> get employeesAdded => _employeeAdded.stream;
addEmployee(Employee employee) async {
final newList = <Employee>..addAll(_employees.value)..add(employee);
await _employeeRepo.upsertEmployee(employee);
_employees.add(newList);
_employeeAdded.add(true);
//FIXME: Save to db
}
Note there is no seedValue in employeeAdded, this is to prevent the snackbar from showing on initial load.
In my screen / page I have a scaffold; it's body calls another method which should explain the rest of the code:
Widget _buildBody(EmployeeBloc bloc) {
return StreamBuilder(
stream: bloc.employees,
builder: (context, snapshot) {
if (!snapshot.hasData) {
bloc.employeesAdded.listen(
(_) => Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
),
),
);
bloc.seedEmployees();
return Center(
child: Text("No employees"),
);
}
return _buildList(bloc, snapshot.data);
},
);
}
Note the listen on the bloc with the hasData if.
This works for now, but would like to know if there is a more neat example.
Although its not my favourite answer, I am also not sure if there is a better alternative; this is what I did as a temporary fix for future watchers:
Create a new stream (in my case employeeAdded), upon adding employees, also create an entry into the stream:
final _employees = BehaviorSubject<List<Employee>>(seedValue: List<Employee>());
final _employeeAdded = BehaviorSubject();
// streams (out)
Observable<List<Employee>> get employees => _employees.stream;
Observable<dynamic> get employeesAdded => _employeeAdded.stream;
addEmployee(Employee employee) async {
final newList = <Employee>..addAll(_employees.value)..add(employee);
await _employeeRepo.upsertEmployee(employee);
_employees.add(newList);
_employeeAdded.add(true);
//FIXME: Save to db
}
Note there is no seedValue in employeeAdded, this is to prevent the snackbar from showing on initial load.
In my screen / page I have a scaffold; it's body calls another method which should explain the rest of the code:
Widget _buildBody(EmployeeBloc bloc) {
return StreamBuilder(
stream: bloc.employees,
builder: (context, snapshot) {
if (!snapshot.hasData) {
bloc.employeesAdded.listen(
(_) => Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
),
),
);
bloc.seedEmployees();
return Center(
child: Text("No employees"),
);
}
return _buildList(bloc, snapshot.data);
},
);
}
Note the listen on the bloc with the hasData if.
This works for now, but would like to know if there is a more neat example.
answered Jan 3 at 15:35
Joey RoosingJoey Roosing
1,43231936
1,43231936
can cause issues (memory leak?) because everytime !hasData passes, a new listener is added
– Joey Roosing
Jan 7 at 10:56
add a comment |
can cause issues (memory leak?) because everytime !hasData passes, a new listener is added
– Joey Roosing
Jan 7 at 10:56
can cause issues (memory leak?) because everytime !hasData passes, a new listener is added
– Joey Roosing
Jan 7 at 10:56
can cause issues (memory leak?) because everytime !hasData passes, a new listener is added
– Joey Roosing
Jan 7 at 10:56
add a comment |
Wrap your body
(the child of your Scaffold
, in your case returned by _buildBody
) with a Builder
so you get to write some "free" code with the context
.
Now you can listen to the stream with a handler you provide (like you already did), but this time you register the listener only once per Scaffold
build (and not registering a listener at each event occurred in employeesAdded
stream).
@override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
bloc.employeesAdded.listen(
(_) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
), // SnackBar
);
},
);
return _buildBody(bloc);
},
), // Builder
); // Scaffold
}
add a comment |
Wrap your body
(the child of your Scaffold
, in your case returned by _buildBody
) with a Builder
so you get to write some "free" code with the context
.
Now you can listen to the stream with a handler you provide (like you already did), but this time you register the listener only once per Scaffold
build (and not registering a listener at each event occurred in employeesAdded
stream).
@override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
bloc.employeesAdded.listen(
(_) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
), // SnackBar
);
},
);
return _buildBody(bloc);
},
), // Builder
); // Scaffold
}
add a comment |
Wrap your body
(the child of your Scaffold
, in your case returned by _buildBody
) with a Builder
so you get to write some "free" code with the context
.
Now you can listen to the stream with a handler you provide (like you already did), but this time you register the listener only once per Scaffold
build (and not registering a listener at each event occurred in employeesAdded
stream).
@override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
bloc.employeesAdded.listen(
(_) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
), // SnackBar
);
},
);
return _buildBody(bloc);
},
), // Builder
); // Scaffold
}
Wrap your body
(the child of your Scaffold
, in your case returned by _buildBody
) with a Builder
so you get to write some "free" code with the context
.
Now you can listen to the stream with a handler you provide (like you already did), but this time you register the listener only once per Scaffold
build (and not registering a listener at each event occurred in employeesAdded
stream).
@override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) {
bloc.employeesAdded.listen(
(_) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Employee added'),
), // SnackBar
);
},
);
return _buildBody(bloc);
},
), // Builder
); // Scaffold
}
answered Mar 4 at 20:15
idow09idow09
7829
7829
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54023203%2fflutter-snackbar-display-based-on-stream%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown