vue 3 reactive custom class object with methods - class

Let's say in my component I have simple computed array of items, all of which are type of custom class Item. Item is an object of a custom class with private methods.
// items is a computed array
const items = computed(() => [new Item("first"), new Item("second"),...]);
// item class
class Item{
constructor(itemName){
this.itemName = itemName;
this.inStock = this.#itemInStock(itemName);
// other properties initialized by some other private methods
}
#itemInStock(item){
return items.indexOf(item) !== -1;
}
}
Now I have been reading about reactivity, here, and if I understood vue uses Proxies to catch attempt to read property and Reflects to use binding, but will it catch methods as well? Can I use private methods in class instance and then use that class instance in template?
Private methods should not be accessed directly e.g. Item.itemInStock should fire error.
Please note that I don't intent to use any of my methods directly in template nor anywhere in application (that is why I made them private)

you can use method reactive and toRefs.
first, you can import this methode.
import { reactive, toRefs } from 'vue
second, you change on your computed
const items = computed(() => reactive[new Item("first"), new Item("second"),...]);
and you change return with
return toRefs(items.indexOf(item))
if your data is object, you should add spread in your return
return ...toRefs(items.indexOf(item))

Related

How to add an item to list in setter and notify one by one with provider in Flutter?

I want to add a TaskModel to taskModelList in setter method and then notify which I encounter the bellow error. I know changing the type of setter parameter to List will fix the issue, but is it possible to add a single item to list in set method?
Error:
The return type of getter 'taskModelList' is 'List' which
isn't a subtype of the type 'TaskModel' of its setter 'taskModelList'.
Code:
class TaskViewModel extends ChangeNotifier {
List<TaskModel> _taskModelList = [];
set taskModelList(TaskModel taskModel) {
_taskModelList.add(taskModel);
notifyListeners();
}
List<TaskModel> get taskModelList => _taskModelList;
}
Your setter currently doesn't set the List, rather than adding a new item in it. A setter sets the List with a List value,
set taskModelList(List<TaskModel> taskModelList) {
_taskModelList = taskModelList;
notifyListeners();
}
UPDATE
Remove your setter.
If you just want to add a single item use a custom method
void addItem(TaskModel task) {
_taskModelList.add(task)
notifyListeners();
}
If you are using Provider, I would suggest enriching your TaskViewModel with adding a static of method:
static TaskViewModel of(BuildContext context, {bool listen = false}) {
return Provider.of<TaskViewModel>(context, listen: listen);
}
Then you can easily listen for changes
TaskViewModel.of(context, listen: true).taskModelList
#esentis answer is correct, but it should also be noted that getters and setters are usually not necessary in Dart.
As per the Dart Style Guide
AVOID wrapping fields in getters and setters just to be "safe".
In Java and C#, it's common to hide all fields behind getters and setters (or properties in C#), even if the implementation just forwards to the field. That way, if you ever need to do more work in those members, you can do it without needing to touch the callsites. This is because calling a getter method is different than accessing a field in Java, and accessing a property isn't binary-compatible with accessing a raw field in C#.
Dart doesn't have this limitation. Fields and getters/setters are completely indistinguishable. You can expose a field in a class and later wrap it in a getter and setter without having to touch any code that uses that field.
GOOD:
class Box {
var contents;
}
BAD:
class Box {
var _contents;
get contents => _contents;
set contents(value) {
_contents = value;
}
}

Flutter, why use "static" in the fromJson method?

static TodoEntity fromJson(Map<String, Object> json) {
return TodoEntity(
json['task'] as String,
json['id'] as String,
json['note'] as String,
json['complete'] as bool,
);
}
static TodoEntity fromSnapshot(DocumentSnapshot snap) {
return TodoEntity(
snap.data()['task'],
snap.id,
snap.data()['note'],
snap.data()['complete'],
);
}
I`m studying "fromJson" method right now and
In this example, why they use "static"?
I wonder why
Because fromJson is related the class and not the object (this is the case for every static variable/method)
So from the name fromJson, You need to create TodoEntity object from your json, which means you don't have the object yet which means you can't call fromJson, So using static here is a must,
Another alternative is passing your json via constructor, but using static is must clean and common.
Example without static:
To create new object from json
var json = {...};
TodoEntity todo = TodoEntity();
TodoEntity todo2 = todo.fromJson(json);
or
var json = {...};
TodoEntity todo = TodoEntity();
todo = todo.fromJson(json);
as you can see you need always an object (todo) to call fromJson
but using static
var json = {...};
TodoEntity todo = TodoEntity.fromJson(json);
static means you can call this function without having an object
The static keyword required to implement "Static Factory Method" pattern for methods which are producing new instances of given class.
If these methods were not static, you had to have the an instance of TodoEntity to call them.
But they are static, so there's no need to create any instance to call them:
TodoEntity.fromJson(jsonMap);

how to set custom object with document id to a collection in firestore in flutter?

I defined a dart class A with some string variables and a list of objects of another class B.
I don't find any method function in cloud_firestore module to set this custom object of class A, as a document to the collection, even though custom objects are supported in Firestore. Do I need to convert all the members(strings, lists etc) of class A to JSON format or any other solution available?
In the event that it's inconvenient to create another collection of the related custom class, the only alternative is to build the related class instances yourself.
import Player from // player module
class GameState {
constructor(data) {
this.players = data.players.map(p => new Player(p))
// ...
}
// flatten GameState into a generic JS map
// build one of these on Player also
asFBData() {
const playerFBData = this.players.map(p => p.asFBData())
return { playerFBData, ...other_game_state_here }
}
}
const gameStateConverter = {
toFirestore: gameState => gameState.asFBData(),
fromFirestore: (snapshot, options) => new GameState(snapshot.data(options))
}
you cannot insert/update a plain Dart model. first, you need to your object into JSON data. for this, You can check this answer.
Also, you can check this answer.

CLSA AddChild Default values

I'm using CSLA latest release and trying to add a row with default items to the collection. What I've noticed is the default constructor of the Foo class is called instead of the AddNewCore in the FooList Class. I am unable to get the AddNewCore or the Child_Create methods to get invoked when a new row is added in a XamDataGrid row. (A row is added, but it is from the default constructor of the FooLine Class--i.e. no default values and no MarkAsChild attribute.) Here is the code snippet that is in the FooList class:
protected override FooItem AddNewCore()
{
var item = DataPortal.CreateChild<FooItem>();
MarkAsChild();
Add(item);
return base.AddNewCore();
}
protected override void Child_Create()
{
var item = DataPortal.CreateChild<FooItem>();
MarkAsChild();
Add(item);
base.Child_Create();
}
What am I doing wrong?
AddNewCore() method exists in client side CSLA class 'ExtendedBindingList' with 'void' return type and same method is exists in server side class 'ObservableBindingList' with return type 'ListClass'. So we required to call run time client side method from server side.
Please refer below code for the same.
#if SILVERLIGHT
protected override void AddNewCore()
{
var item = DataPortal.CreateChild<FooItem>();
Add(item);
}
#endif
For information: The reason the above code does not work has to do with the way WPF invokes the New method. Typically, in other frameworks it is possible to hook on to that event, intercept it, and return with default data. With WPF, it is necessary to check the RecordAdding, or RecordAdded trigger events and process the invocations by hand.
In my case, the WPF would look like:
<i:Interaction.Triggers>'
i:EventTrigger EventName="RecordAdded">
<ei:CallMethodAction TargetObject="{Binding}"
MethodName="CreateDefaultAddressValuesCommand" />
</i:EventTrigger>
In the view model:
var idx = FooInformation.FooAddressList.Count - 1;
var address = await FooAddress.CreateAsync();
FooListing.FooAddressList[idx] = address;

MEF and IObservables

I have a singleton IObservable that returns the results of a Linq query. I have another class that listens to the IObservable to structure a message. That class is Exported through MEF, and I can import it and get asynchronous results from the Linq query.
My problem is that after initial composition takes place, I don't get any renotification on changes when the data supplied to the Linq query changes. I implemented INotifyPropertyChanged on the singleton, thinking it word make the exported class requery for a new IObservable, but this doesn't happen.
Maybe I'm not understanding something about the lifetime of MEF containers, or about property notification. I'd appreciate any help.
Below are the singleton and the exported class. I've left out some pieces of code that can be inferred, like the PropertyChanged event handlers and such. Suffice to say, that does work when the underlying Session data changes. The singleton raises a change event for UsersInCurrentSystem, but there is never any request for a new IObservable from the UsersInCurrentSystem property.
public class SingletonObserver: INotifyPropertyChanged
{
private static readonly SingletonObserver _instance = new SingletonObserver();
static SingletonObserver() { }
private SingletonObserver()
{
Session.ObserveProperty(xx => xx.CurrentSystem, true)
.Subscribe(x =>
{
this.RaisePropertyChanged(() => this.UsersInCurrentSystem);
});
}
public static SingletonObserverInstance { get { return _instance; } }
public IObservable<User> UsersInCurrentSystem
{
get
{
var x = from user in Session.CurrentSystem.Users
select user;
return x.ToObservable();
}
}
}
[Export]
public class UserStatus : INotifyPropertyChanged
{
private string _data = string.Empty;
public UserStatus
{
SingletonObserver.Instance.UsersInCurrentSystem.Subscribe(sender =>
{
//set _data according to information in sender
//raise PropertyChanged for Data
}
}
public string Data
{
get { return _data; } }
}
}
My problem is that after initial composition takes place, I don't get any renotification on changes when the data supplied to the Linq query changes.
By default MEF will only compose parts once. When a part has been composed, the same instance will be supplied to all imports. The part will not be recreated unless you explicitly do so.
In your case, if the data of a part change, even if it implements INotifyPropertyChanged, MEF will not create a new one, and you don't need to anyway.
I implemented INotifyPropertyChanged on the singleton, thinking it word make the exported class requery for a new IObservable
No.
Maybe I'm not understanding something about the lifetime of MEF containers, or about property notification.
Property notification allows you to react to a change in the property and has no direct effect on MEF. As for the container's lifetime, it will remain active until it is disposed. While it is still active, the container will keep references to it's compose parts. It's actually a little more complex than that, as parts can have different CreationPolicy that affects how MEF holds the part, I refer you to the following page: Parts Lifetime for more information.
MEF does allow for something called Recomposition. You can set it likewise:
[Import(AllowRecomposition=true)]
What this does tough is allow MEF to recompose parts when new parts are available or existing parts aren't available anymore. From what I understand it isn't what you are referring to in your question.