Can't access Meteor.user() property - meteor

I've installed a Meteor phone authentication package mys:accounts-phone, which should add a phone.number subfield into users collection. I try to access this field as follows:
Meteor.user().phone.number
but typescript shows error
Property 'phone' does not exist on type 'User'.
On the other hand, I have custom props in users.profile, and can easily access them in this way.
Insecure is not yet removed. Autopublish is ON.

this happens sometime when our angular component is initialized but our meteor data is not reached from server.
try to use user injection in place of Meteor.user()
import {Component} from "#angular/core";
import { InjectUser } from 'angular2-meteor-accounts-ui';//<--**** import this****
#Component({
selector: "login-buttons",
template
})
#InjectUser('user') //<--*** add this***
export class LoginButtonsComponent {
user: Meteor.User; //<--*** add this ***
constructor(private router: Router) {}
}
now in user variable you will have all values of Meteor.User
if you want to print in html part use this
<div *ngIf="user">
{{user.phone.number}}
</div>
don't forget to install
meteor add accounts-password
meteor npm install --save angular2-meteor-accounts-ui
and in app.module.ts file
import { AccountsModule } from 'angular2-meteor-accounts-ui';
#NgModule({
imports: [
... other modules here
AccountsModule
],
hope this will work. if this not work let me know i will tell you one other solution

Got probable answer from Meteor docs.
It explains why username property appears. By default, Meteor publish only a number of fields considered to be public. To exposure any additional fields they must be published explicitly.
Not yet have time to test, but think it should work.
The other reason, with the same sympthoms, when publication code do not executed at server side. Try to put
Meteor.startup(() => {
// code to run on server at startup
Meteor.publish('userData', function() {
if(!this.userId) return null;
return Meteor.users.find(this.userId
//, {fields: {lastname: 1,}}
);
});
});
in a file within /server folder of your application.

Related

Vue 3 components with slots in vendor folder

I have an issue where I want to extract all my components out into a separate repository but I want to load them in via composer instead of npm (business decision).
This was all working fine. Add it as a dependancy in the composer.json file and then add the following to the webpack.mix.js file;
mix.webpackConfig({
resolve: {
alias: {
'#ui' : path.resolve(__dirname, 'vendor/companyname/ui/src'),
}
}
});
And then use the following to import them in;
import PrimaryButton from "#ui/buttons/primary";
Which all worked fine!
Until I wanted to use slots. If I include a slot I get the following error;
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'nodeName')
at new create (svg.js?1929:3616)
at globalRef.SVG (svg.js?1929:31)
at Proxy.mounted (Editor.vue?721f:63)
at callWithErrorHandling (runtime-core.esm-bundler.js?5c40:154)
at callWithAsyncErrorHandling (runtime-core.esm-bundler.js?5c40:163)
at Array.hook.__weh.hook.__weh (runtime-core.esm-bundler.js?5c40:2909)
at flushPostFlushCbs (runtime-core.esm-bundler.js?5c40:357)
at flushJobs (runtime-core.esm-bundler.js?5c40:393)
In this example the component looks like this;
<template>
<button #click="click">
<slot></slot>
</button>
</template>
<script>
export default {
emits: ['click'],
methods: {
click() {
this.$emit('click')
}
}
}
</script>
Now, if I copy this component into the project repository and load it in that way, there is no error and works as intended!
Can anyone point me in the direction of where I am going wrong please.
Update
I have removed other components from view I'm rendering and now have a new error;
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'isCE')
at renderSlot (runtime-core.esm-bundler.js?c099:5832)
at Proxy.render (primary.vue?f782:3)
at renderComponentRoot (runtime-core.esm-bundler.js?5c40:1166)
at componentEffect (runtime-core.esm-bundler.js?5c40:5201)
at reactiveEffect (reactivity.esm-bundler.js?a1e9:42)
at effect (reactivity.esm-bundler.js?a1e9:17)
at setupRenderEffect (runtime-core.esm-bundler.js?5c40:5154)
at mountComponent (runtime-core.esm-bundler.js?5c40:5113)
at processComponent (runtime-core.esm-bundler.js?5c40:5071)
at patch (runtime-core.esm-bundler.js?5c40:4673)
Update
This is not the answer but the reason for this, from what I can tell is that there were two instances of Vue in play, one from the library and one in my application. I have no idea how to stop this but if I push the contents up to a repo and pull it in via npm then it works normally. Still would like to know how to get this running locally without using npm.

Meteor packages dynamic imports fail with templating as weak dependency

The Package
I have a shared library as Meteor package with the following structure:
ui
- componentA.html
- componentA.js
- loader.js
- ...
tools
- toolXY.js
- ...
and while tools are shared among many of my apps (and the ui), the ui part is only used by one app. Consider the template to be totally simple:
componentA.html
<template name="componentA">
<span>yea component A</span>
</template>
componentA.js
import { Template } from 'meteor/templating'
import { toolXY } from '../tools/toolXY'
import './componentA.html'
// ... template code
loader.js (little helper, think the package has 100 ui components)
export const loader = {
componentA: {
template: 'componentA',
load: async function () {
return import('./componentA')
}
}
}
Because the ui is used in one app only, I made the templating and dynamic-import a weak dependency:
Package.onUse(function (api) {
api.versionsFrom('1.6')
api.use('ecmascript')
api.use('dynamic-import', ['client'], { weak: true })
api.use('templating', ['client'], { weak: true })
})
The Problem
I add my package and the weak dependencies to a project via
$ meteor add dynamic-import templating me:mypackage
and import the ui on the client like the following:
client/main.js
import { loader } from 'meteor/me:mypackage/ui/loader'
Meteor.startup(() => {
loader.componentA.load()
.then(() => console.log('loaded'))
.catch(e => console.error(e))
})
It will result in the following error:
Error: "Cannot find module './componentA.html'"
makeMissingError http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:232
resolve http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:238
moduleLink http://localhost:5050/packages/modules.js?hash=88e9e724ccc8459066fbe9e3889ef37c7bb7067f:353
module /node_modules/meteor/me:mypackage/ui/componentA.js:16
makeModuleFunction http://localhost:5050/packages/dynamic-import.js?hash=cf582bcc349503492678c9fd3f7bba4a610f70e5:138
fileEvaluate http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:346
require http://localhost:5050/packages/modules-runtime.js?hash=23fe92393aa44a7b01bb53a510a9cab5fb43037c:248
moduleLink http://localhost:5050/packages/modules.js?hash=88e9e724ccc8459066fbe9e3889ef37c7bb7067f:360
getNamespace http://localhost:5050/packages/dynamic-import.js?hash=cf582bcc349503492678c9fd3f7bba4a610f70e5:187
dynamicImport http://localhost:5050/packages/dynamic-import.js?hash=cf582bcc349503492678c9fd3f7bba4a610f70e5:40
Checking for Package.templating inside loader.js, as well as componentA.js resolves to Object { Template: Template(viewName, renderFunction) } (because it has been installed as package to the project).
The fix that isn't really a fix
If I turn off the weak dependency on templating it will work fine:
api.use('templating')
This, however, will cause all my applications to load templating, allthough they do not require it.
The question
Why is it behaving like this? Shouldn't this work with weak dependency when the dependency has been added to the project?

Angular2 routing: canDeactivate limitations

I've got a form in angular2. If it's dirty (with unsaved changes), I want to restrict the user from navigating away.
Research shows that the canDeactivate route guard is the way to do it.
Google led me to this github file which seems to implement what I want.
import { CanDeactivate } from '#angular/router';
import { FormGroup } from '#angular/forms';
export interface FormComponent {
form: FormGroup;
}
export class PreventUnsavedChangesGuard implements CanDeactivate < FormComponent > {
canDeactivate(component: FormComponent) {
if (component.form.dirty)
return confirm('You have unsaved changes. Are you sure you want to navigate away?');
return true;
}
}
Now, I've put this service in my project, injected it in my form component, added it to my routing module as so...
const routes: Routes = [{
path: '',
loadChildren: 'app/main/main.module#MainModule',
canActivate: [AuthenticationGuard],
}, {
path: 'login',
component: LoginComponent,
canDeactivate: [PreventUnsavedChangesGuard]
}, ]
and included it in the app module's providers array.
Now, it seems to work. In case I have unsaved changes when I click the browser's back button. I get the confirmation dialog. However, when I input a new URL in the address bar, I don't get the confirmation. Also, I'm able to close the tab when I have unsaved changes.
Are these known limitations of canDeactivate, or am I doing something wrong. How do I get the behavior I want? (Confirmation dialog if the user attempts to close tab or navigate away using the address bar?)

meteor publish composite does not

I have problems when I try use meteor-publish-composite. I see this page https://github.com/englue/meteor-publish-composite and I execute the following code in my meteor project:
meteor add reywood:publish-composite
I create publish-composite function like this:
import { Meteor } from 'meteor/meteor';
import { Categories } from '../../../../both/collections/administration/category.collection';
import { Structures } from '../../../../both/collections/administration/structure.collection';
//Meteor.publish('categories', () => Categories.find());
Meteor.publishComposite('categoriesWithStructures', {
find: () => {
return Categories.collection.find();
},
children: [{
find:(category) => {
console.log(category);
return Structures.collection.find({_id: category.structure});
}
}]
});
But when I initialize the project, in the console I see the message:
Property 'publishComposite' does not exist on type 'typeof Meteor'
In the .meteor/packages file the meteor module is added
angular2-compilers
accounts-password
msavin:mongol
reywood:publish-composite
My meteor project use Angular2.
I will appreciate any help. Regards.
I have the same problem.
My solution looks like
Meteor["publishComposite"] (...)
instead of
Meteor.publishComposite (...)
I'm also using typescript for meteor, and I think that its not bet combo (yet).

How can I change the subscriptions query parameters in react-komposer (meteor) from a child component?

I'm building an app with Meteor using the react-komposer package. It is very simple: There's a top-level component (App) containing a search form and a list of results. The list gets its entries through the props, provided by the komposer container (AppContainer). It works perfectly well, until I try to implement the search, to narrow down the results displayed in the list.
This is the code I've started with (AppContainer.jsx):
import { Meteor } from 'meteor/meteor';
import { composeWithTracker } from 'react-komposer';
import React, { Component } from 'react';
import Entries from '../api/entries.js';
import App from '../ui/App.jsx';
function composer(props, onData) {
if (Meteor.subscribe('entries').ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
export default composeWithTracker(composer)(App);
App simply renders out the whole list of entries.
What I'd like to achieve, is to pass query parameters to Entries.find({}).fetch(); with data coming from the App component (captured via a text input e.g.).
In other words: How can I feed a parameter into the AppContainer from the App (child) component, in order to search for specific entries and ultimately re-render the corresponding results?
To further clarify, here is the code for App.jsx:
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>
<form>
<input type="text" placeholder="Search" />
</form>
<ul>
{this.props.entries.map((entry) => (
<li key={entry._id}>{entry.name}</li>
))}
</ul>
</div>
);
}
}
Thanks in advance!
I was going to write a comment for this to clarify on nupac's answer, but the amount of characters was too restrictive.
The sample code you're looking for is in the search tutorial link provided by nupac. Here is the composer function with the corresponding changes:
function composer(props, onData) {
if (Meteor.subscribe('entries', Session.get("searchValues")).ready()) {
const entries = Entries.find({}).fetch();
onData(null, {entries});
};
};
The solution is the session package. You may need to add it to your packages file and it should be available without having to import it. Otherwise try with import { Session } from 'meteor/session';
You just need to set the session when submitting the search form. Like this for instance:
Session.set("searchValues", {
key: value
});
The subscription will fetch the data automatically every time the specific session value changes.
Finally, you'll be able to access the values in the publish method on the server side:
Meteor.publish('entries', (query) => {
if (query) {
return Entries.find(query);
} else {
return Entries.find();
}
});
Hope this helps. If that's not the case, just let me know.
There are 2 approaches that you can take.
The Subscription way,
The Meteor.call way,
The Subscription way
It involves you setting a property that you fetch from the url. So you setup your routes to send a query property to you Component.Your component uses that property as a param to send to your publication and only subscribe to stuff that fits the search criteria. Then you put your query in your fetch statement and render the result.
The Meteor.call way
Forget subscription and do it the old way. Send your query to an endpoint, in this case a Meteor method, and render the results. I prefer this method for one reason, $text. Minimongo does not support $text so you cannot use $text to search for stuff on the client. Instead you can set up your server's mongo with text indexes and meteor method to handle the search and render the results.
See what suits your priorities. The meteor.call way requires you to do a bit more work to make a "Search result" shareable through url but you get richer search results. The subscription way is easier to implement.
Here is a link to a search tutorial for meteor and read about $text if you are interested

Resources