How does a Meteor database mutator know if it's being called from a Meteor.method vs. normal code? - methods

If one does something on the client like
Foo.insert({blah : 1})
where Foo is a Meteor collection, this actually triggers a Meteor.method call as documented in the last paragraph of http://docs.meteor.com/#meteor_methods that executes code on both the client and the server.
However, let's say I define a method (on client and server) that does the same thing:
Meteor.methods({
bar: function() {
Foo.insert({blah : 1})
}
});
Now, I trigger this on the client with
Meteor.call("bar");
Foo.insert will now be called both on the client and the server as a result of the method. However, how does the client-side invocation of insert know not to call the server again, since it is itself a method?
Moreover, is there a way to call insert on the client side without automatically triggering the canonical server-side latency-compensation call and resulting synchronization? (For why I'd want to do this, see Loading a Meteor client app with fake fire-and-forget data)

The client side one becomes a 'stub'. It has this isSimulation property set that makes it appear as if the data is inserted for latency compensation.
I think if a .method is run on the client the latency compensation is always enabled and it shouldn't enter in the database. So anything running on a client side method would be a 'fake' type simulation
If you try setting this.isSimulation to false you'll get some weird error that shows you that the client side insert starts to throw errors with the insert.
I'm not too sure how to run it in a false simulation. I think you'd have to run it off in some other method var dothis = function() {...} type method.
To do this 'fake fire' & forget and have client side only data, which is what I presume (please correct if I'm wrong so I change the answer) modify the _collection property in your client side method.
e.g if you have
mydata = new Meteor.Collection("something");
function something() {
mydata.insert({..});
}
Modify the method to do this instead
mydata._collection.insert({..});
This will make sure that the data isn't synchronized to the server, yet will have the local collection have this 'fake data'.
Hope this helps!

Related

Variable inside socket.on('connect') not updating

This React with Socket.io.
[canPass, setCanPass] = useState(true)
[example, setExample] = useState('')
useEffect(()=>{
if(socket !== ''){
setCanPass(false)
console.log(example)
if(canPass){
socket.on('connect', ()=>{
console.log(example)
})
}
}
},[socket, example])
This code is inside of a Provider, so the variable "example" will change often.
Initial value of "socket" is an empty string. After the socket is created, the effect will set the listener "connect".
The flag "canPass" avoids setting the listener over and over any time the effect gets triggered.
NOW THE PROBLEM IS: Variable "example" updates normally inside of the Effect, but when the listener function is triggered (let's say server drops and reestablish, or user turn off and on wifi) variable "example" INSIDE of the listener function remains unchanged.
Any ideas how to fix this? Thanks!!
EDIT -> FIXED!
I don't really understand why this question is not that frecuent as I expected. Ok, so, the thing is an event can link more than one listener, and each listener is an instance of the function, it means, it creates a separated scope and the variables inside wont update.
To fix it, I just added another effect, observing the changes of variable "example", ereasing the listener with the method removeAllListeners() and set it again with the new values of "example". And that's it.

Creating a simple, basic page object in Nightwatch.js

Ok, so I've read up on the use of page_objects in nightwatch.js, but I'm still getting issues with it (which I'm convinced is due to something obvious and/or simple).
Using http://nightwatchjs.org/guide/#page-objects as the guide, I added the the file cookieremoval.js in my page_objects folder.
module.exports = {
elements: {
removeCookies: {
selector: '.banner_continue--2NyXA'
}
}
}
In my nightwatch.conf.js file I have;
page_objects_path: "tests/functional/config/page_objects",
And in my test script I have;
module.exports = {
"/cars/road-tax redirects to /car-tax/ ": browser => {
browser.url(browser.launch_url + browser.globals.carReviews)
.assert.urlEquals(browser.launchUrl + "/car-reviews/")
.waitForElementPresent('#cookieRemove', 3000)
.click('#cookieRemove')
.end();
},
};
However, when I run the test, I keep getting an error reading;
Timed out while waiting for element <#cookieRemove>
Any ideas why this is not working?
Many thanks
First of all, you never instantiated your page object. You're asking the browser object to search for an unknown element, that's why it's timing out. Your code should look something like this in your test script: var cookieRemoval = browser.page.cookieremoval(); then use this object to access those variables and functions in your page object. For example, if you wanted to access the remove cookie element, then you would do this cookieRemoval.click('#removeCookies');.
Secondly, you will have to know when to use the global browser object and when to use your page object. If you need to access something within your page object, obviously use the page object to call a function or access a variable. Otherwise, browser won't know the element you're looking for exists. Hope this help you out, I would definitely spend some more time learning about objects and specifically how they're used in nightwatch.js.

Socket.io: Client receiving empty object/array despite data existing on server

I'm working with socket.io. I am having trouble receiving data from the server even though I can console.log() the data (an array of objects) right before I try to emit the data back to the calling client. If I hard code info into the emit, it will display on the client but when I use the dynamically created array of objects, it doesn't go through. My gut tells me its a asyn issue but I'm using bluebird to manage that. Perhaps its an encoding issue? I tried JSON.stringify and JSON.parse, no dice.
Server
socket.on('getClassList', function(){
sCon.getClassList()
.then(function(data){
console.log(data) //data is an array full of objects
socket.emit('STC_gotDatList', data)
})
})
Hard-Coded Expected Output:
classes['moof'] = {
accessList: [888],
connectedList: [],
firstName: "sallyburnsjellyworth"
}
Client
socket.on('STC_gotDatList', function(info){
console.log(info) //prints [] or {}
})
EDIT:
I remember reading somewhere that console.log() may not be printing data at the time the data is available/populated. Could that be it even though im using Promises? At the time I'm emitting the data, it just hasn't been populated into the array? How would i troubleshoot this scenario?
EDIT2:
A step closer. In order to get anything to return, for some reason I have to return each specific object in the 'classes' array. It wont allow me to send the entire array, for the example I gave above, to get data to the client, I have to return(classes['moof']), can't return(classes) to get the entire array... Not sure why.
EDIT3: Solution: You just can't do it this way. I had to put 'moof' inside classes as a property (className) and then I was able to pass the whole classes array.
How is the 'classes' array created?
The problem might be that it is being given properties dynamically, but has not been created as an object, but rather an array.
If you plan to dynamically add properties to it (like property moof), you should create it as an object (with {}) rather than an array (with []).
Try
var classes = {};//instead of classes = []
//then fill it however you do it
classes[property] = {
accessList: [888],
connectedList: [],
firstName: "sallyburnsjellyworth"
};
Also, the credit goes to Felix, I'm just paraphrasing his answer: https://stackoverflow.com/a/8865468/7573546

Meteor 0.5.9: replacement for using Session in a server method?

So, I was attempting to do something like the following:
if(Meteor.isServer){
Meteor.methods({connect_to_api: function(vars){
// get data from remote API
return data;
}});
}
if(Meteor.isClient){
Template.myTpl.content = function(){
Meteor.call('connect_to_api', vars, function(err,data){
Session.set('placeholder', data);
});
return Session.get('placeholder');
};
}
This seemed to be working fine, but, of course, now breaks in 0.5.9 as the Session object has been removed from the server. How in the world do you now create a reactive Template that uses a server-only (stuff we don't want loading on the client) method call and get data back from that Method call. You can't put any Session references in the callback function because it doesn't exist on the server, and I don't know of any other reactive data sources available for this scenario.
I'm pretty new to Meteor, so I'm really trying to pin down best-practices stuff that has the best chance of being future-proof. Apparently the above implementation was not it.
EDIT: To clarify, this is not a problem of when I'm returning from the Template function. This is a problem of Session existing on the server. The above code will generate the following error message on the server:
Exception while invoking method 'connect_to_api' ReferenceError: Session is not defined
at Meteor.methods.connect_to_api (path/to/file.js:#:#)
at _.extend.protocol_handlers.method.exception ... etc etc
Setting the session in the callback seems to work fine, see this project I created on github: https://github.com/jtblin/meteor_session_test. In this example, I return data in a server method, and set it in the session in the callback.
There are 2 issues with your code:
1) Missing closing brace placement in Meteor.methods. The code should be:
Meteor.methods({
connect_to_api: function(vars) {
// get data from remote API
return data;
}
});
2) As explained above, you return the value in the session, before the callback is completed, i.e. before the callback method had the time to set the session variable. I guess this is why you don't see any data in the session variable yet.
I feel like an idiot (not the first time, not the last). Thanks to jtblin for showing me that Session.set does indeed work in the callback, I went back and scoured my Meteor.method function. Turns out there was one spot buried in the code where I was using Session.get which was what was throwing the error. Once I passed that value in from the client rather than trying to get it in the method itself, all was right with the world.
Oh, and you can indeed order things as above without issue.

Ajax-Enabled WCF Only Intermittently Returns to Callback Function

I have an ajax-enabled WCF service that returns a set of JSON objects back to the browser. The service has a simple function that calls a business layer dll. This then returns the objects to the calling method.
Below is the service implementation (minus the Imports statements):
<ServiceContract(Namespace:="")> _
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
<ServiceBehavior(IncludeExceptionDetailInFaults:=True, MaxItemsInObjectGraph:=5000)> _
Public Class NoteService
<OperationContract()> _
Public Function GetAllInsuredNotes(ByVal insuredID As Integer) As List(Of NoteExport)
Dim allNotes As New List(Of NoteExport)
Using nr As New NoteRepository()
allNotes = nr.GetInsuredNotesForExport(insuredID)
If allNotes Is Nothing Then
Throw New InvalidOperationException("The operation to retrieve notes caused an error.")
End If
End Using
Return allNotes.ToList()
End Function
The Javascript to call my service is as follows:
function exportToExcel(sender, eventArgs) {
var insuredID = $('input[id*=hdnInsuredID]').val();
NoteService.GetAllInsuredNotes(insuredID, OnNoteGetSuccess, OnNoteGetFailure, null);
}
function OnNoteGetSuccess(result) {
var insuredID = $('input[id*=hdnInsuredID]').val();
OutputExcel(insuredID, result);
return true;
}
function OnNoteGetFailure(result) {
alert('There was an error retrieving notes for export. Please contact the help desk for assistance.');
return false;
}
Basically my problem is this. Everything seems to work fine from the server side function standpoint. Every time I call the function client side, the server side code executes and the result is generated. However, the success callback function only gets called periodically. I can invoke the function several times and only have the callback executed once. The problem seems to grow worse the larger the result set returned.
I could understand if it was related to the MaxObjectsInGraph setting, but the problem isn't that the result never comes back if I have a large amount of data. It will come back sometimes every forth or fifth try, sometimes 2 tries in a row, sometimes 1 in ten tries. It seems very random.
I have spent at least 2 days racking my brain on this one and can't seem to discover the solution. Does anyone have any insight on this?
Ok, I figured out what was happening and thought I'd post it here in case anyone else experiences this kind of issue. Using fiddler was the tool that put me on the right track.
Basically, the link button I was using to make the call to the javascript function was calling a full page postback, not just calling the javascript function. So if the request was small enough, the response to the web service call came quickly and the web page ran the callback function with the new JSON data it received. As the data sets got larger, sometimes the response would come back in time for the page to process the results. However, sometimes the response wouldn't come back until the full page postback was complete and the reference to the callback function was lost. So it would get back the JSON data but wouldn't know what to do with it.
So I had the javascript function called by the link button always return false to cancel the post back and the problem was solved.
I only had one other issue to deal with and that was setting the MaxObjectsInGraph setting for the service to a high enough value to account for the JSON size coming back. The only thing I still find odd is that if this setting was not high enough, I would get a challenge response box asking for a login name for the first couple of attempts, then the service would just come back with an unknown status code.
In any case, I hope this post proves helpful to someone else.
I don't think we can help you figure it out either unless we have the JavaScript definition for
NoteService.GetAllInsuredNotes(insuredId, CallBack1, CallBack2, WhatIsThisParam)

Resources