While uploding the image i'm getting below error at server console.
I20200123-18:57:34.751(5.5)? Exception while invoking method 'collections.images.insert' TypeError: Cannot read property 'insert' of undefined
I20200123-18:57:34.753(5.5)? at MethodInvocation.collections.images.insert (imports/api/collections/methods.js:20:31)
I20200123-18:57:34.753(5.5)? at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1771:12)
I20200123-18:57:34.753(5.5)? at DDP._CurrentMethodInvocation.withValue (packages/ddp-server/livedata_server.js:719:19)
I20200123-18:57:34.754(5.5)? at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1234:12)
I20200123-18:57:34.754(5.5)? at DDPServer._CurrentWriteFence.withValue (packages/ddp-server/livedata_server.js:717:46)
I20200123-18:57:34.754(5.5)? at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1234:12)
I20200123-18:57:34.754(5.5)? at Promise (packages/ddp-server/livedata_server.js:715:46)
I20200123-18:57:34.755(5.5)? at new Promise (<anonymous>)
I20200123-18:57:34.755(5.5)? at Session.method (packages/ddp-server/livedata_server.js:689:23)
I20200123-18:57:34.755(5.5)? at packages/ddp-server/livedata_server.js:559:43
Here, I'm providing my code snippets for your referance.
Collection constructor server Code :
import { FilesCollection } from 'meteor/ostrio:files';
const Collections_Images = new FilesCollection({
collectionName: 'collections_images',
storagePath: 'uploads/Collections-Images',
allowClientCode: false,
onBeforeUpload(file) {
// Allow upload files under 10MB, and only in png/jpg/jpeg formats
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.extension)) {
return true;
}
return 'Please upload image, with size equal or less than 10MB';
}
});
export default Collections_Images;
Created method Code :
import { Meteor } from 'meteor/meteor';
import { Collections_Images } from './collections_img.js';
Meteor.methods({
'collections.images.insert'(images) {
return Collections_Images.insert({
file : images,
streams: 'dynamic',
chunkSize: 'dynamic',
})
},
});
Client side js code:
"change #myFileInput" : function(event){
const images = event.currentTarget.files[0];
Meteor.call('collections.images.insert',images, (error) => {
if(error){
alert("collection image insert : "+error.message);
}
else{
images=null;
}
});
}
Thanks in advance.
You export default from './collections_img.js'
But you import it like this:
import { Collections_Images } from './collections_img.js';
You need to import it like this
import Collections_Images from './collections_img.js';
And .insert() method is on client side code, there is no need of sending file over the Meteor.method
Related
I'm working on creating a server-side extension in JupyterLab and have been searching for quite a while for a way to get the currently active notebook name inside my index.ts file. I found this existing extension that gets the currently active tab name with ILabShell and sets the browser tab to have the same name. In my case I'll be triggering the process with a button on the notebook toolbar so the active tab will always be a notebook. However, when I try to use the code in the activate section of my extension, I get TypeError: labShell.currentChanged is undefined where labShell is an instance of ILabShell. That extension doesn't support JupyterLab 3.0+ so I believe that's part of the problem. However, currentChanged for ILabShell is clearly defined here. What if anything can I change to make it work? Is there another way to accomplish what I'm trying to do? I'm aware of things like this to get the notebook name inside the notebook but that's not quite what I'm trying to do.
Windows 10,
Node v14.17.0,
npm 6.14.13,
jlpm 1.21.1,
jupyter lab 3.0.14
I'm using this example server extension as a template: https://github.com/jupyterlab/extension-examples/tree/master/server-extension
index.ts file from the existing extension to get the current tab name:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import { Title, Widget } from '#lumino/widgets';
/**
* Initialization data for the jupyterlab-active-as-tab-name extension.
*/
const extension: JupyterFrontEndPlugin<void> = {
id: 'jupyterlab-active-as-tab-name',
autoStart: true,
requires: [ILabShell],
activate: (app: JupyterFrontEnd, labShell: ILabShell) => {
const onTitleChanged = (title: Title<Widget>) => {
console.log('the JupyterLab main application:', title);
document.title = title.label;
};
// Keep the session object on the status item up-to-date.
labShell.currentChanged.connect((_, change) => {
const { oldValue, newValue } = change;
// Clean up after the old value if it exists,
// listen for changes to the title of the activity
if (oldValue) {
oldValue.title.changed.disconnect(onTitleChanged);
}
if (newValue) {
newValue.title.changed.connect(onTitleChanged);
}
});
}
};
export default extension;
My index.ts file:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import { ICommandPalette } from '#jupyterlab/apputils';
import { ILauncher } from '#jupyterlab/launcher';
import { requestAPI } from './handler';
import { ToolbarButton } from '#jupyterlab/apputils';
import { DocumentRegistry } from '#jupyterlab/docregistry';
import { INotebookModel, NotebookPanel } from '#jupyterlab/notebook';
import { IDisposable } from '#lumino/disposable';
import { Title, Widget } from '#lumino/widgets';
export class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
constructor(app: JupyterFrontEnd) {
this.app = app;
}
readonly app: JupyterFrontEnd
createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
// dummy json data to test post requests
const data2 = {"test message" : "message"}
const options = {
method: 'POST',
body: JSON.stringify(data2),
headers: {'Content-Type': 'application/json'
}
};
// Create the toolbar button
let mybutton = new ToolbarButton({
label: 'Measure Energy Usage',
onClick: async () => {
// POST request to Jupyter server
const dataToSend = { file: 'nbtest.ipynb' };
try {
const reply = await requestAPI<any>('hello', {
body: JSON.stringify(dataToSend),
method: 'POST'
});
console.log(reply);
} catch (reason) {
console.error(
`Error on POST /jlab-ext-example/hello ${dataToSend}.\n${reason}`
);
}
// sample POST request to svr.js
fetch('http://localhost:9898/api', options);
}
});
// Add the toolbar button to the notebook toolbar
panel.toolbar.insertItem(10, 'MeasureEnergyUsage', mybutton);
console.log("MeasEnerUsage activated");
// The ToolbarButton class implements `IDisposable`, so the
// button *is* the extension for the purposes of this method.
return mybutton;
}
}
/**
* Initialization data for the server-extension-example extension.
*/
const extension: JupyterFrontEndPlugin<void> = {
id: 'server-extension-example',
autoStart: true,
optional: [ILauncher],
requires: [ICommandPalette, ILabShell],
activate: async (
app: JupyterFrontEnd,
palette: ICommandPalette,
launcher: ILauncher | null,
labShell: ILabShell
) => {
console.log('JupyterLab extension server-extension-example is activated!');
const your_button = new ButtonExtension(app);
app.docRegistry.addWidgetExtension('Notebook', your_button);
// sample GET request to jupyter server
try {
const data = await requestAPI<any>('hello');
console.log(data);
} catch (reason) {
console.error(`Error on GET /jlab-ext-example/hello.\n${reason}`);
}
// get name of active tab
const onTitleChanged = (title: Title<Widget>) => {
console.log('the JupyterLab main application:', title);
document.title = title.label;
};
// Keep the session object on the status item up-to-date.
labShell.currentChanged.connect((_, change) => {
const { oldValue, newValue } = change;
// Clean up after the old value if it exists,
// listen for changes to the title of the activity
if (oldValue) {
oldValue.title.changed.disconnect(onTitleChanged);
}
if (newValue) {
newValue.title.changed.connect(onTitleChanged);
}
});
}
};
export default extension;
There are two ways to fix it and one way to improve it. I recommend using (2) and (3).
Your order of arguments in activate is wrong. There is no magic matching of argument types to signature function; instead arguments are passed in the order given in requires and then optional. This means that you will receive:
...[JupyterFrontEnd, ICommandPalette, ILabShell, ILauncher]
but what you are expecting is:
...[JupyterFrontEnd, ICommandPalette, ILauncher, ILabShell]
In other words, optionals are always at the end. There is no static type check so this is a common source of mistakes - just make sure you double check the order next time (or debug/console.log to see what you are getting).
Actually, don't require ILabShell as a token. Use the ILabShell that comes in app.shell instead. This way your extension will be also compatible with other frontends built using JupyterLab components.
shell = app.shell as ILabShell
(optional improvement) install RetroLab as a development-only requirement and use import type (this way it is not a runtime requirement) to ensure compatibility with RetroLab:
import type { IRetroShell } from '#retrolab/application';
// ... and then in `activate()`:
shell = app.shell as ILabShell | IRetroShell
to be clear: not doing so would not make your extension incompatible; what it does is ensures you do not make it incompatible by depending on lab-specific behaviour of the ILabShell in the future.
So in total it would look like:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import type { IRetroShell } from '#retrolab/application';
// ...
const extension: JupyterFrontEndPlugin<void> = {
id: 'server-extension-example',
autoStart: true,
optional: [ILauncher],
requires: [ICommandPalette],
activate: async (
app: JupyterFrontEnd,
palette: ICommandPalette,
launcher: ILauncher | null
) => {
let shell = app.shell as ILabShell | IRetroShell ;
shell.currentChanged.connect((_, change) => {
console.log(change);
// ...
});
}
};
export default extension;
I'm trying to get my head around Meteor's Tracker.autorun and Tracker.dependancy features.
I'm trying to do something that seems simple in my mind but I'm struggling to execute.
I have a server-side function, that I register as a method:
let count = 0
setInterval(()=>{
count ++
return count
}, 1000)
export default count
Register as a method:
import count from './setIntervarl'
Meteor.methods({
getData:function() {
return count
}
});
And then call up on the client side:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker'
import './main.html';
// Setup reactive variable
rv1 = new ReactiveVar(9)
Meteor.call('getData', function(error, results) {
if(error){
console.log("error:"+error);
} else {
rv1.set(results)
}
});
// Display the output from reactiveVar
Template.someData.helpers({
someData: function() {
return rv1.get();
}
})
Can someone please show me how to use Tracker.autorun or Tracker.dependancy so that my UI updates with interval that is set in my server-side function
I'm having really trouble getting this working.
Many thanks
There will be no reactivity out of the box here. Meteor methods are not reactive but just a wrapped ddp call to a server (rpc-) endpoint that returns something.
In order to gain reactive data from the server, you need to subscribe to a publication. If you want only this counter being published, you may create a collection with a single document and publish it.
imports/CountCollection.js (both)
export const CountCollection = new Mongo.Collection('myCounter')
server/counter.js (server)
import { CountCollection } from '../imports/CountCollection'
let counterDocId
Meteor.startup(() => {
// optional: clear the collection on a new startup
// this is up to your use case
// CountCollection.remove({})
// create a new counter document
counterDocId = CountCollection.insert({ count: 0 })
// use the Meteor.setInterval method in order to
// keep the Meteor environment bound to the execution context
// then update the counter doc each second
Meteor.setInterval(function () {
CountCollection.update(counterDocId, { $inc: { count: 1 } })
}, 1000)
})
// Now we need a publication for the counter doc.
// You can use the `limit` projection to restrict this to a single document:
Meteor.publish('counterDoc', function () {
if (!counterDocId) this.ready()
return CountCollection.find({ _id: counterDocId }, { limit: 1 })
})
Now you can subscribe to this publication and get reactive updates to the document:
client/someData.js (client)
import { CountCollection } from '../imports/CountCollection'
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker'
import './main.html';
// Setup reactive variable
const reactiveCounter = new ReactiveVar(0)
const counterSubscription = Meteor.subscribe('counterDoc')
Template.someData.onCreated(() => {
const instance = this
instance.autorun(() => {
// counterSubscription.ready() will re-called
// when the publication released a new cursor
// which causes the autorun to re-run = reactivity
if (counterSubscription.ready()) {
// there is only 1 doc published, so no query require
const counterDoc = CountCollection.findOne()
reactiveCounter.set(counterDoc && counterDoc.count)
}
})
})
// Display the output from reactiveVar
Template.someData.helpers({
someData: function() {
return reactiveCounter.get()
}
})
Sidenote:
don't forget to get the paths and imports correct
Readings:
https://docs.mongodb.com/manual/reference/operator/update/inc/
https://docs.meteor.com/api/timers.html#Meteor-setInterval
I am having difficulties with meteor 1.6. First, I have created a database instance and tried to subscribe in the client. through form, I am able to input the data into my database. But could not retrieve it through the subscribe. can anybody tell me what wrong have I done in my code?
import { Template } from "meteor/templating";
import { Notes } from "../lib/collection";
import { Meteor } from "meteor/meteor";
// import { ReactiveDict } from 'meteor/reactive-dict';
import "./main.html";
/*
Template.body.onCreated(function bodyOnCreated() {
this.state = new ReactiveDict();
Meteor.subscribe("db1");
}); */
Template.Display.helpers({
notes() {
Meteor.subscribe("db1");
return Meteor.call('data');
}
});
Template.body.events({
"click .delete": function() {
Notes.remove(this._id);
},
"submit .formSubmit": function(event) {
event.preventDefault();
let target = event.target;
let name = target.name.value;
Meteor.call("inputs", name);
target.name.value = "";
return false;
},
"click .userDetail": function() {
if (confirm("Delete the user Detail ?")) {
Notes.remove(this._id);
}
}
});
here is the code for publication :
import { Mongo } from 'meteor/mongo';
export const Notes = new Mongo.Collection('notes');
Meteor.methods({
inputs:(name)=> {
if (!Meteor.user()) {
throw Meteor.Error("Logged in");
}
Notes.insert({
name: name,
createdAt: new Date()
});
},
data:()=>{
return Notes.find({});
}
});
Meteor.subscribe("notes"); should be in Template.body.onCreated lifycycle method. you need to write a
publish code seperately and not inside the Meteor.method. see below format,
Meteor.publish('notes', function tasksPublication() {
return Notes.find({});
});
Inside the helper just call the subscribed Collection a below,
Template.Display.helpers({
notes() {
return Notes.find({});
}
});
**NOTE: ** Never use Meteor.call inside the helper method. helpers are reactive and real time.
I'm trying to subscribe to a subject. This is working as expected the first time but throwing the above error the second time and I can't see where to fix it.
export function uploadSceneFile(action$, store) {
return action$.ofType(CREATE_SCENE_SUCCESS)
.mergeMap(({payload}) =>
UploadSceneWithFile(payload)
.map(res => {
if (res.progress > 0){
return { type: UPLOAD_SCENE_PROGRESS, scene: res }
}
else if(res.progress === -1){
return { type: UPLOAD_SCENE_SUCCESS, scene: res }
}
})
)
}
It's designed to listen for the scen being created, dispatch upload progress notifications and then dispatch the success message.
The error gets thrown straight away from this line the second time it runs
onProgress: (val)=> subject$.next({...scene,progress:val}),
export function UploadSceneWithFile(scene){
const subject$ = new Subject()
scene.filename = scene.file.name
scene.type = scene.file.type.match('image') ? 0 : 1
FileToScenePreview(scene).then(res => {
scene.thumbName = res.thumbName
})
const uploader = new S3Upload({
getSignedUrl: getSignedUrl,
uploadRequestHeaders: {'x-amz-acl': 'public-read'},
contentType: scene.file.type,
contentDisposition: 'auto',
s3path: 'assets/',
onError:()=>subject$.next('error'),
onProgress: (val)=> subject$.next({...scene,progress:val}),
onFinishS3Put: ()=> {
subject$.next({...scene,progress:-1})
subject$.complete()
},
})
uploader.uploadFile(scene.file)
return subject$.asObservable()
}
ERROR MESSAGE
Subscriber.js:242 Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
at Object.performAction (<anonymous>:1:40841)
at liftAction (<anonymous>:1:34377)
at dispatch (<anonymous>:1:38408)
at createEpicMiddleware.js:59
at createEpicMiddleware.js:59
at SafeSubscriber.dispatch [as _next] (applyMiddleware.js:35)
at SafeSubscriber../node_modules/rxjs/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:238)
at SafeSubscriber../node_modules/rxjs/Subscriber.js.SafeSubscriber.next (Subscriber.js:185)
at Subscriber../node_modules/rxjs/Subscriber.js.Subscriber._next (Subscriber.js:125)
at Subscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at SwitchMapSubscriber../node_modules/rxjs/operators/switchMap.js.SwitchMapSubscriber.notifyNext (switchMap.js:126)
at InnerSubscriber../node_modules/rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
at InnerSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at MergeMapSubscriber../node_modules/rxjs/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:145)
at InnerSubscriber../node_modules/rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
at InnerSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at MergeMapSubscriber../node_modules/rxjs/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:145)
at InnerSubscriber../node_modules/rxjs/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:23)
at InnerSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at MapSubscriber../node_modules/rxjs/operators/map.js.MapSubscriber._next (map.js:85)
at MapSubscriber../node_modules/rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at Subject../node_modules/rxjs/Subject.js.Subject.next (Subject.js:55)
at S3Upload.onProgress (uploadSceneFile.js:27)
at S3Upload.<anonymous> (s3upload.js:139)
In the inner map within your uploadSceneFile, you have an if statement followed by an else if statement, of if neither is true, the map will return undefined instead of an action.
.map(res => {
if (res.progress > 0){
return { type: UPLOAD_SCENE_PROGRESS, scene: res }
}
else if(res.progress === -1){
return { type: UPLOAD_SCENE_SUCCESS, scene: res }
}
// An action should be returned here!
})
Note that, when passed an undefined action, the check that Redux performs to determine whether or not an action is a plain object will effect the error you are seeing.
import { Meteor } from 'meteor/meteor';
Meteor.methods({
'harmonized'(text){
HTTP.call( 'GET', 'https://hts.usitc.gov/api/search', { params: {
"query": text
}}, function( error, response ) {
if ( error ) {
console.log( error );
} else {
return response.data.results;
}
});
}
});
The above code gives me the array of objects in my terminal
import './shipping_steps.html';
import { HTTP } from 'meteor/http'
Template.shipping_steps.events({
// data: [],
'submit .hs': function(){
event.preventDefault();
//get Input value
const target = event.target;
const text = target.search.value;
//clear the form
target.search.value = "";
const data = Meteor.call('harmonized', text);
console.log(data);
return false;
}
})
When I try to store the array of objects on the client, I am not
able to do so and client logs out as undefined. However, for this
code, it is grabbing information from an input field on client
From your code data hasn't returned a value yet. You need to store the result on a reactive variable or a session variable.