How should BloC be structured in Flutter? - dart

I'm new to BloC and Flutter. For a single simple screen it should works without problem. But let's take a look at my case, I'm confused on how to use the BloC pattern.
I have a single screen called Container, which container a PageView of Content screen. Say I have 5 pages within that PageView. These pages count is dynamic. The pages only differ the data.
I'm thinking about 2 ways of implementing this:
1/ Using ONE single bloc and pass it to my 5 child Content.
2/ Using one bloc for the Container and another bloc for the Content. So this seems to be nested blocs. the ContainerBloc will contains the list of ContentBloc.
For the 1st approach. The problem that I see is the re-rendering problem. I will create a list of data of each page:
List<List<String>> allData = [];
BehaviorSubject<List<List<String>>> _allData = BehaviorSubject<List<List<String>>>();
Observable<List<String>> getData(index) => _allData.stream.map((list) => list[index]); //This stream returns the list at the index
and each page will listen to the data by:
//StreamBuilder in the UI
stream: widget.bloc.getData(index);
and the update method for the data should be like:
void updateData(int index, List<String> newData) {
List<String> temp = allData[index];
temp.add(newData);
allData[index] = temp;
_allData.sink.add(allData);
}
As I understand, once one page is updated. All other page will re-render because they all listen to the getData(index) stream which will be triggered by the_allData.sink.add(allData);
So I think all pages will be re-rendered even though the data of that page is not changed.
For the 2nd approach. I don't know if it would be best practice to have nested bloc like that. There maybe some case when the ContainerBloc must listen to some of the ContentBloc output.
I'm kinda confused now.
Thank you for your time.

Related

How to run a specific method when props changes in Svelte3?

I'm building an autocomplete text field component. We will show popup of items filtered based on what users type. It is going to be async, I will get the details from the server and do some filtering based on the text typed in the field.
So here, I have run this filtering logic whenever I send new data to the component.
I come from angular, there we used to have ngOnChange(). Is there something similar available in svelte3.
Right now, I'm filtering by calling the method from outside by binding bind:this. I don't feel like this is a correct approach.
https://github.com/manojp1988/svelte3-autocomplete/blob/master/dev/App.svelte
Without stores, using a prop
Just using a prop:
export let search = '';
....
$: if (search !== '') { // make it react to changes (in the parent)
doSomeThing(search);
};
Stores
Svelte also has stores. A store is an observable object which can be observed everywhere even beyond you project with RxJS.
Example:
const unsubscribe = search.subscribe(s) => {
doSomeThing(s);
});
onDestroy(unsubscribe);
In another component you can use search.set('Hi');
But looking forward for other solutions to handle these kind of changes in parent <-> child components or calling child Component methods.
From child to parent we can fire events.
But from parent to child ...? we can use a store or Component bind:this or ..? but ....

How to manage a stream of List of objects in Flutter?

I've been dabbling with flutter for a few days, and I'm trying to make a simple ToDo app, as a learning project. I'm trying to implement something like a BLoC. A list of ListItem widgets is built with ListView.builder, wrapped in StreamBuilder. I have implemented a StreamController'<'List'<'Note'>'>', and whenever I add a new Note to the list, I've managed to add it to a temporary list and then pass the list through the StreamSink, though I suspect it rebuilds the whole ListView each time an item is added.
I'm trying to learn piece by piece, to understand streams in isolation. What is a better way of implementing this? I'm only able to find examples of simple types like Stream but not for complex types like Lists.
class Note {
String title, note;
Note(this.title, this.note);
}
class ListBloc {
final notes = <Note>[];
final _controller = StreamController<List<Note>>.broadcast();
get controllerOut => _controller.stream.asBroadcastStream();
get controllerIn => _controller.sink;
addNewNote(Note note) {
notes.add(note);
controllerIn.add(notes);
}
void dispose() {
_controller.close();
}
}
I'm sure there's a better approach, that will add a new entry to the ListView. I've tried to not use any external packages since I just want to learn the basics.
For adding and removing items from the list, there's nothing wrong with rebuilding the whole list (That's how it's supposed to work).
But, for constantly updating items in the list, you can have a substream for each item to update only that item when it changes.

How to reload a ResourceTable programmatically in Laravel Nova?

I have a custom resource-tool (ledger entry tool) that modifies values of a resource as well as insert additional rows into related resources.
"Account" is the main resources.
"AccountTransaction" and "AccountLog" both get written to when a ledger entry is created. And through events, the account.balance value is updated.
After a successful post of a ledger entry (using Nova.request) in the resource-tool, I would like the new balance value updated in the account detail panel, as well as the new entries in AccountTransaction and AccountLog to be visible.
The simple way would be to simply reload the page, but I am looking for a more elegant solution.
Is it possible to ask these components to refresh themselves from within my resource-tool vue.js component?
Recently had the same issue, until I referred to this block of code
Nova has vuex stores modules, where they have defined storeFilters.
Assigning filters an empty object and then requesting them again "reloads" the resources. Haven't done much more research on this matter, but if you are looking for what I think you are looking for, this should be it.
async reloadResources() {
this.resourceName = this.$router.currentRoute.params.resourceName || this.$router.currentRoute.name;
if (this.resourceName) {
let filters_backup = _.cloneDeep(this.$store.getters[`${this.resourceName}/filters`]);
let filters_to_change = _.cloneDeep(filters_backup);
filters_to_change.push({});
await this.$store.commit(`${this.resourceName}/storeFilters`, filters_to_change);
await this.$store.commit(`${this.resourceName}/storeFilters`, filters_backup);
}
},

Angular taking DOM snapshot

I am trying to record the content of a div which is populated using ng-repeat, sort of like taking a snapshot of that div at certain moments so that I don't have to write more code to persist data.
link: function(scope, element, attrs) {
scope.game = game;
var $element = $(element),
$clone = $element.children().clone();
scope.$watch('someVariable',function(array){
if (array[array.length - 1] === scope.id){
record($compile($clone)(scope));
console.log($compile($clone)(scope));
}
},true);
}
I've been trying variations of code like this but could not get any luck, I've never been able to deep copy the content of the div generated by ng-repeat
any suggestions on how I could copy the exact dynamically genereted content of the div at certain point of time?
If you have the data to present in a ng-repeat you already have the data in the model, you just have to save a snapshot of that data to other object in the Scope. You should manipulate the data in the controller instead of trying to access the DOM directly, this is a big no no in angularjs. Then if you need a Div to reuse, just make a Directive that knows how to present those snapshots you saved in the model.

Dynamically Loading LI's in JQueryMobile 1.0

I've just updated my project from jquerymobile 1.0a1 to version 1.0.
I've encountered a problem with dynamic content. Based on an ajax search I populate an unordered list with list items. Previous the following code refreshed the list so that all the styling appeared correctly:
$('#myContent').find("ul").listview();
$('#myContent').find("ul").listview('refresh');
However as of 1.0 this no longer seems to work.
The list appears but the styling is all wrong and the data-theme on all the elements gets ignored.
Has anyone come across a similar issue with updating and come across the solution.
Updating lists If you add items to a listview, you'll need to call the refresh() method on it to update the styles and create
any nested lists that are added. For example:
$('#mylist').listview('refresh');
Note that the refresh() method only affects new nodes appended to a
list. This is done for performance reasons. Any list items already
enhanced will be ignored by the refresh process. This means that if
you change the contents or attributes on an already enhanced list
item, these won't be reflected. If you want a list item to be updated,
replace it with fresh markup before calling refresh.
http://jquerymobile.com/demos/1.0/docs/lists/docs-lists.html
if #myContent is the listview you can do this:
$('#myContent').listview('refresh');
if #myContent is the page you can do something like this:
$('#myContent').trigger('create');
Create vs. refresh: An important distinction Note that there is an important difference between the create event and refresh method
that some widgets have. The create event is suited for enhancing raw
markup that contains one or more widgets. The refresh method should be
used on existing (already enhanced) widgets that have been manipulated
programmatically and need the UI be updated to match.
For example, if you had a page where you dynamically appended a new
unordered list with data-role=listview attribute after page creation,
triggering create on a parent element of that list would transform it
into a listview styled widget. If more list items were then
programmatically added, calling the listview’s refresh method would
update just those new list items to the enhanced state and leave the
existing list items untouched.
http://jquerymobile.com/demos/1.0/docs/pages/page-scripting.html
What you want can be achieved by replacing your 2 lines of code with the following:
$('#myContent ul').listview('create');
Hope this helps...
I've had this issue. The reason you are getting things all messed up is you are initalizing and refreshing the element multiple times. I noticed I had 2 different functions running that would call .listview('refresh') on the same element. After I took one out the themes and data went back to looking normal. Also are you getting any JS errors?
EDIT:
To be more specific you are calling .listview() somewhere in your code 2 times which is initializing it twice. I would wait to before you page is loaded to run the refresh so you only call it once.
Another thing you could do is check if the element is initialized already or not so you don't do it twice. Just check the element or in some cases the parent to see if the class ui-listview is present.
var element = $('#myContent').find('ul');
if ($(element).hasClass('ui-listview')) {
//Element is already initialized
$(element).listview('refresh');
} else {
//Element has not been initiliazed
$(element).listview().listview('refresh');
}
Just an FYI you can chain those events to look like $('#myContent').find('ul').listview().listview('refresh');
It cand be achived through.
$('#myContent').listview('refresh');
The below snippet shows you to load data from xml and dynamically create a list view.
function loadData()
{
$.ajax({
url:"BirthdayInvitations.xml",
dataType: "xml",
success: function(xml)
{
$(xml).find("event").each(function()
{
$("#mymenu").append('<li>' + this.textContent + ' </li>');
});
$("#mymenu").listview('refresh');
}
});
}
See if this is related to ur question http://www.amitpatil.me/demos/jquery-mobile-twitter-app/ and this one also http://www.amitpatil.me/demos/ipad-online-dictionary-app/
In first example i am using listview('refresh'); method and in second example i am using
$(document).page("destroy").page();

Resources