VueJS3 ref/reactive array of object keys - vuejs3

I want to watch the keys of an object, outside of a normal Vue component.
I think something like this should be possible with reactive, but no luck yet:
var myObject = {};
var keys = reactive(Object.keys(myObject));
myObject['fish'] = 200;
//keys is still []
Also tried:
var keys = reactive({keylist: Object.keys(myObject)});
var keys = ref(Object.keys(myObject));

Finally got it, it's a combination of reactive and the watchEffect. I'm still open to cleaner answers if this is anti-pattern somehow.
var myObject = reactive({});
var keys;
watchEffect(() => {
keys = Object.keys(myObject);
});

Related

How do I apply an array values to Mongodb find() in ASP.net

I want to retrieve the specific data using an array-values, but I don't know how to deal with it.
URL is like http://localhost/api/data?sym=aa&bb&cc
DB documents are like:
{"symbol":"aa","price":1.1}
{"symbol":"bb","price":1.2}
{"symbol":"cc","price":1.3}
{"symbol":"dd","price":1.4}
{"symbol":"ee","price":1.5}
the expected result is:
[
{"symbol":"aa","price":1.1}
{"symbol":"bb","price":1.2}
{"symbol":"cc","price":1.3}
]
My code is:
[HttpGet()]
public IEnumerable<Data> Get(string sym)
{
symbol = sym.Split('&');
//connect to database and collections
var client = new MongoClient("mongodb+srv://.....");
var db = client.GetDatabase("...");
var _portf = db.GetCollection<Data>("...");
return _portf.Find(???).ToList();
}
??? is where I have failed to find a solution. or I am completely wrong with the find() method.
I really need your help. Thank you!
Find takes in a FilterDefinition object. For example, a common way of getting a document from MongoDB by its ID would be:
public T LoadRecordById<T>(string table, Guid id)
{
var collection = db.GetCollection<T>(table);
var filter = Builders<T>.Filter.Eq("Id", id);
return collection.Find(filter).First();
}
You can combine multiple FilterDefinition objects together using the Or method:
var filter1 = Builders<T>.Filter.Eq("symbol", symbol);
var filter2 = Builders<T>.Filter.Eq("symbol", symbol);
var filter3 = Builders<T>.Filter.Eq("symbol", symbol);
var filter = Builders<T>.Filter.Or(filter1, filter2, filter3);
Hope this helps (it does not hurt to be nice, does it, #Dharman?)
I've found a very promising way which works perfectly. Thanks to this video
rewrite the code"
[HttpGet()]
public IEnumerable<Data> Get(string sym)
{
var symlist = sym.Split('&');
//connect to database and collections
var client = new MongoClient("mongodb+srv://.....");
var db = client.GetDatabase("...");
var _portf = db.GetCollection<Data>("...");
-->var fitlerDefinition = Builders<Findata>.Filter.In(a => a.Symbol, symlist);
return _portf.Find(fitlerDefinition).ToList();
}

How to bind/referece grand parent property to/inside child knockout

Hi guys looking for some basic advice.
I have four models: BoardViewModel, List, Card, Member
var Member = function (id, name, avatar) {
var self = this;
self.id = id;
self.name = name;
self.avatar = avatar;
self.isChecked = ko.observable(false);
};
I am instantiating members property inside BoardViewModel. But I want to use a copy of this model inside each Card model to instantiate a list of assigned members.
Each card stores comma separated list of member references like
",1,2,4,5"
I am writing a loop to BoardViewModel.members and mark members as checked if id references match bore I assign it as Card.members.
The last piece of the puzzle I am missing is reference to the BoardViwModel.members.
I have a lovely example fiddler that would somewhat help to build a picture of what I am talking about.
Just bear in mind that once I have this working properly I want to replace view() binding
foreach: $root.members
with
foreach: members
If at all possible I would like to avoid passing BoardViewModel.members as parameter into List and then into Card.
Update 1
As suggested by #Jeroen here's a simplified version of my fiddler.
The top view() model which encompases a concept of lists:
var BoardViewModel = function (lists, members) {
var self = this;
// in reality members are fetched via ajax call to the server
// and instantiate as a ko.observableArray()
self.groupMembers = ko.observableArray(members);
self.lists = ko.observableArray(lists);
...
}
In reality this has a signature like this:
var boardViewModel = function (initialData)
moving on.
The child List model which encompases a concept of cards:
var List = function (id, name, cards, sortOrder, groupMembers) {
var self = this;
self.cards = ko.observableArray(cards);
...
}
in reality:
var list = function (item, groupMembers)
nothing special there really.
The child Card model which encompases the concept of card items (but lets not go there yet):
var Card = function (id, title, description, contentItemId, members, groupMembers) {
var self = this;
self.members = ko.observableArray(parseMembers(members));
// now remember each card has a members property
// which stores comma separated list ",1,4"
function (members) {
var memberList = groupMembers;
var memberRefList = members.split(',');
ko.utils.arrayForEach(memberList, function(member){
ko.utils.arrayForEach(memberRefList, function(memberId){
if(member.id === meberId) {
member.isChecked(true);
}
});
});
return memberList;
}
...
}
in reality:
var card = function (item, groupMembers)
nothing too fancy there either.
I currently have something like this working on my dev environment.
Problem:
Those with keen eyes probably noticed the way I was passing groupMembers all the way up. I am not particularly hyped about the idea.
Anyone know a better way of implementing this? i.e. why can't I just do something like
var memberList = self.parent.parent.groupMembers;
for instance.
As per me, the better way to do is to have the child viewmodels inside the parent view-model. like this where you can access the parent data members as well as methods directly.
ViewModel
var BoardViewModel = function(){
var self = this;
this.members = ko.observableArray();
this.lists = ko.observableArray();
// Child View Models
this.Member = function(member){
this.id = member.id;
this.name = member.name;
this.avatar = member.avatar;
this.isChecked = ko.observable(false);
}
this.List = function(list){
// same for this
};
this.Card = function(card){
// same for this
};
// a Method to bind the data with the observables and arrays
// Assuming data is a json object having Members, List objects
this.applyData = function(data){
self.members(jQuery.map(data.Members, function(item){
return new self.Member(item);
}));
self.lists(jQuery.map(data.Lists, function(item){
return new self.List(item);
}));
}
}
onDom ready
// json object holding your data
var data = {
"Members" : [
],
"Lists" : [
],
"Cards" : [
]
};
var vm = new BoardViewModel();
$(function(){
ko.applyBindings(vm, document.getElementById('myModule'));
vm.applyData(data);
});

How to write Meteor.wrapAsync fs.readFile?

I need a function that emits individual lines from a file with newlines. Nothing hard.
But with node, it is hard, and with Meteor, there's an additional complication: you must use Meteor.wrapAsync. Surprisingly, there isn't an example of how to use wrapAsync in the docs, and I could only find a couple of examples online, none of which helped.
I have something like:
var readFileAsync = function (file, cb) {
// From here to below comment works synchronously
var instream = fs.createReadStream(file, function () {
var outstream = new stream;
outstream.readable = true;
outstream.writable = true;
var rl = readline.createInterface({
input: instream,
output: outstream,
terminal: false
});
rl.on('line', function(line) {
console.log(line);
return line;
});
});
// Reference to aforementioned comment
};
var readWatFile = Meteor.wrapAsync(readFileAsync);
var line = readWatFile('/path/to/my/file');
console.log(line);
I know this is wrong because it doesn't work, so how do I write this?
There are two ways to go around it.
Load the whole file into memory and do whatever you want. To do that you can use the Private Assets API
Use node.js streams and stream the file line by line. You would have something like this.
Example code that you would need to tweak to your favorite streaming methods:
var Future = Npm.require('fibers/future');
var byline = Npm.require('byline');
var f = new Future;
// create stream in whatever way you like
var instream = fs.createReadStream(...);
var stream = byline.createStream(instream);
// run stream handling line-by-line events asynchronously
stream.on('data', Meteor.bindEnvironment(function (line) {
if (line) console.log(line)
else future.return();
}));
// await on the future yielding to the other fibers and the line-by-line handling
future.wait();

Meteor - reactive template value not from database

I would like to have a template value {{abc}} that is reactive to changes triggered by other code in my application, but it is not a database field. I have seen the Session variable being used for this but is this the only way?
Please have a look at meteor documentation with examples.
From there:
var weather = "sunny";
var weatherDep = new Deps.Dependency;
var getWeather = function () {
weatherDep.depend()
return weather;
};
var setWeather = function (w) {
weather = w;
// (could add logic here to only call changed()
// if the new value is different from the old)
weatherDep.changed();
};
So everytime you call setWeather() the dependency in getWeather() will be flagged as changed and call any reactive functions to run again with the new value.

Can I pass a function closure (with my parameters) as Firebase's set() method 'oncomplete' argument?

I want to do further processing depending on the success or failure of the set() method, but I need the context of some objects at the time I call the set() method. Otherwise my objects will be out of scope when the oncomplete function is called unless I put them in global - which I don't really want to do.
Here is an example:
function oncomplete_AddTran(tran,client,appt,balance){
/* if named argument 'balance' exists it is safe to assume
Firebase has not 'stepped on' the arguments with it's single
Error object or null */
if(balance typeof object) console.log("my parameters made it here");
}
function addTran(tran, client, appt, balance) {
var TRANS_LOCATION = 'https://xxx.firebaseIO.com/testing/transactions';
var tranListRef = new Firebase(TRANS_LOCATION);
var oncomplete = function() {
oncomplete_AddTran(tran, client, appt, balance); };
var tranref = tranListRef.child(tran.name).set(tran.literal, oncomplete);
}
Yes, it is possible. I am too impatient waiting for the confirmation I was looking for and decided to test myself. Here is the code I used (that works for my purpose):
function oncomplete_AddTran(tran,client,appt,balance){
console.log("arguments passed:" + arguments.length);
// firebase original arguments :: arguments.callee.caller.arguments
var fbargs = arguments.callee.caller.arguments;
}
function addTran(tran, client, appt, balance) {
var TRANS_LOCATION = "https://xxx.firebaseIO.com/testing/transactions";
var tranListRef = new Firebase(TRANS_LOCATION);
var oncomplete = function() {
oncomplete_AddTran(tran, client, appt, balance); };
var tranref = tranListRef.child(tran.name).set(tran.literal, oncomplete);
}
function main() {
var tran = {}; tran.name = "test1"; tran.literal = { tran: "tran" };
var client = {}; client.literal = { client: "client" };
var appt = {}; appt.literal = { appt:"appt" };
var balance = {}; balance.literal = { balance:"balance" };
addTran(tran,client,appt,balance);
}
The arguments were passed as expected but I still don't know how Firebase's set() method will pass the error object to the callback (in the event of an error) because I haven't tried reproducing an error and don't really know if I can.
The default null, and another (undefined) that is supposed to be passed when there is no error is not found in arguments.callee.caller.arguments (see callback function in example above). I am not sure that what I am doing is good practice - seems a bit hacky to me so I won't accept this answer to the question (yet).

Resources