I would like to turn off the automatic app refresh in meteor that occurs every time I change a file. How do I do this?
You can start your app with the --once flag, like so: meteor --once.
You can disable HCP (hot code push) by adding this anywhere in your client code:
Meteor._reload.onMigrate(function() {
return [false];
});
After doing that, you'll need to manually refresh the page in order to see any new changes.
Building on those David's response, here's how I've been doing it to let components stop hot code push while they are alive:
let shouldReloadPage = false;
const componentsBlockingHCP = [];
Meteor._reload.onMigrate(function() {
if (componentsBlockingHCP.length) {
shouldReloadPage = true;
return [false];
}
shouldReloadPage = false;
return [true];
});
/*
* Prevent hot push
*/
export const delayHCP = (component) => {
if (componentsBlockingHCP.indexOf(component) < 0)
componentsBlockingHCP.push(component);
};
/*
* Enable, and reload if hot pushed has been requested when it was not available
*/
export const stopHCPDelay = (component) => {
const idx = componentsBlockingHCP.indexOf(component);
if (idx !== -1)
componentsBlockingHCP.splice(idx, 1);
if (shouldReloadPage && !componentsBlockingHCP.length) {
location.reload();
}
};
And then, from a component (with React syntax):
componentDidMount() {
delayHCP(this);
}
componentWillUnmount() {
stopHCPDelay(this);
}
There is a small trick for that. Put # in the end of the url of the page you are working and press Enter, then continue to work on your code. Once you save the file, page will not be refreshed till you refresh it manually (F5 or cmd + R) This way will prevent the page to refresh, but the new code is still pushed to the client and you don't need to disable the HCP for the whole site. Disadvantage: you don't know when the new code is pushed to the client
Related
so I have a problem this problem with my app. I'm not sure what is the right way to implement this autosaving feature. When you change the note's title or it's content, there is a debounce function that goes off in 2 seconds and if you change to the current note before the debounce update is complete it never updates. Let me know if I've done a poor job of explaining or if there is something that I need to clarify, Thanks!
Here's a video of what occurs: https://www.loom.com/share/ef5188eec3304b94b05960f403703429
And these are the important methods:
updateNoteTitle(e) {
this.noteData.title = e.target.innerText;
this.debouncedUpdate();
},
updateNoteContent(e) {
this.noteData.content = e;
this.debouncedUpdate();
},
debouncedUpdate: debounce(function () {
this.handleUpdateNote();
}, 2000),
async handleUpdateNote() {
this.state = "loading";
try {
await usersCollection
.doc(this.userId)
.collection("notes")
.doc(this.selectedNote.id)
.update(this.noteData)
.then(() => this.setStateToSaved());
} catch (error) {
this.state = "error";
this.error = error;
}
},
setStateToSaved() {
this.state = "saved";
},
Why running every two seconds ?
And an async wait is a really bad approach in a component.
To autosave the note I recommend that you add an eventListener on window closing or on changing the tab event, Like in the video provided (whatever event suits you best)
created () {
window.addEventListener('beforeunload', this.updateNote)
}
Where your updateNote function is not async.
But if you really want to save on each change.
You can make a computed property that looks like this:
note: {
get() {
return this.noteData.title;
},
set(value) {
this.noteData.title = value;
this.state= 'loading'
usersCollection.doc(this.userId)
.collection("notes")
.doc(this.selectedNote.id)
.update(this.noteData)
.then(() => this.setStateToSaved());
}
},
And the add v-model="note" to your input.
Imagine the user will type 10 characters a second That's 10 calls meaning 10 saves
EDIT:
Add a property called isSaved.
On Note change click if(isSaved === false) call your handleUpdateNote function.
updateNoteTitle(e) {
this.noteData.title = e.target.innerText;
this.isSaved = false;
this.debouncedUpdate();
}
and in your function setStateToSaved add this.isSaved = true ;
I don't know if your side bar is a different component or not.
If it is, and you are using $emit to handle the Note change, then use an event listener combined with the isSaved property.
I have a note taking app which allows users to add notes. I am trying to render newly created notes on the home page, but when I go to the add note and add a note, then go back to the home page, it shows the new notes(limited to 10) but the new note that was just created is at the bottom of the list, instead of the top. When I refresh the page, it goes to the top like I want it to. How would I get it so that I don't have to refresh the page to get the newly created note at the top?
I try to sort by using a timestamp, (using Date.parse(new Date())), and then publishing from server using this,
Meteor.publish('notes-newest', function () {
return Notes.find({},{sort: {createdAt: -1}, limit: 10});
});
Here is where I am trying to render it:
componentDidMount() {
Meteor.subscribe('notes-newest')
this.tracker = Tracker.autorun(() => {
const notes = Notes.find().fetch()
if(notes == null || notes == undefined){
return;
}
this.setState({ notes });
console.log(notes);
})
}
You need to do the sort on the client as well.
this.tracker = Tracker.autorun(() => {
const notes = Notes.find({},{sort: {createdAt: -1}).fetch()
If still you dont get the data as you want then you can try below code
this.tracker = Tracker.autorun(() => {
const notes = Notes.find({},{sort: {createdAt: -1}).fetch()
var data = notes.reverse()
You will get your data in descending order while displaying
if people log into my Meteor 1.3.1 app from more than one tab/browser they're going to have problems.
So, when a user logs in, I'd like to log them out everywhere else, and park them on a "you logged in somewhere else" page.
I tried a couple things: Accounts.logoutOtherClients() looked promising, but seems to be broken. This logs everyone out.
if (Meteor.isClient) {
// FF 1 tab, Chrome 2 tabs.
// FF login -> chrome logs out ok.
// Chrome login -> FF logs out. Then Chrome other tab logs in. Then both Chrome tabs logout.
Accounts.onLogin(function() {
console.log(Meteor.loggingIn()); // false. See https://github.com/meteor/meteor/issues/1616
Accounts.logoutOtherClients();
});
}
Before that I was working on a hand-rolled solution, but it seemed like Meteor.logout() would logout both tabs in the same browser. The best I could get was window.location="https://google.com"
NOTE: The approach below doesn't work if user closes all tabs. When they re-open app, they don't have a tabToken, so can never login again.
What's the way to do this?
The best way I can think to do this is:
1) At Meteor.start() on the client make a unique tabToken
2) Save token to Session variable on client
3) At login save tabToken to user
4) On client, listen to Meteor.user().profile for tabToken changes.
if (Meteor.isClient) {
// Make a unique tabToken at startup.
Meteor.startup(function() {
var tabToken = (0|Math.random()*9e6).toString(36); // jshint ignore:line
Session.set('tabToken', tabToken);
console.log('startup TabToken ' + Session.get('tabToken'));
});
// onLogin, set the active tab to our tabToken
Accounts.onLogin(function() {
Meteor.call('setActiveTab', Session.get('tabToken'), function() {
// When method returns, watch profile for tabToken changes
console.log('setActiveTab tabToken ' + Session.get('tabToken'));
console.log('setActiveTab Meteor.user().profile.tabToken ' + Meteor.user().profile.tabToken);
Tracker.autorun(function (c) {
// If the tabToken changes to a different token, logout
if (Meteor.user()) {
var userTabToken = Meteor.user().profile.tabToken;
if (userTabToken && !Session.equals('tabToken', userTabToken)) {
window.location = 'https://google.com';
// Doesn't work
// c.stop();
// Meteor.logout(); // ERROR this logs out all tabs in browser.
// Router.go('loggedOut');
}
}
});
});
});
}
// Make a meteor method to set tabToken
if (Meteor.isServer) {
Meteor.methods({
setActiveTab: function(tabToken) {
if(!tabToken) throw new Meteor.Error('noTabToken');
console.log('setActiveTab ' + tabToken);
if (!Meteor.user()) return;
Meteor.users.update(Meteor.userId(), {
$set: {
'profile.tabToken': tabToken
}
});
}
});
}
This just seems really kludgy. Any other suggestions?
Mike
I'm building a simple database for small pixel-art files. The images are saved directly to the database:
Template.pixUpload.events({
'change .myPixInput': function(event, template) {
event.preventDefault();
var file = event.target.files[0]; //assuming 1 file only
if (!file) return;
var reader = new FileReader();
reader.onload = function(event){
MyPix.insert({
binary: reader.result,
createdAt: new Date
});
}
reader.readAsDataURL(file);
}
})
The idea is to be able to modify the images on their way back to the browser, scale them on the fly (if things don't get too slow). So I'm trying to read the image from the db, and scale it with Imagemagick, before displaying it. It doesn't work – and I can't find anything helpful I would be able to understand:
Template.pixList.helpers({
'thumbnail': function() {
var bin = this.binary;
var thumb = new FileReader();
Imagemagick.convert(['bin', '-filter', 'point', '64x64', 'thumb']);
return thumb;
}
})
im using GM Package Right now, take a look at full repo here
First Install All FSCollecton Packages.
GridFS (Because you say you want to store the file inside MongodB).
Graphicsmagick meteor add cvs:graphicsmagick
Second Declare collections on /lib/collection.js
kaiStackExample = new FS.Collection("kaiStackExample ", {
stores: [new FS.Store.GridFS("kaiStackExample ",{
beforeWrite:function(fileObj){
return {
extension: 'png',
type: 'image/png'
};
},
transformWrite:function(fileObj, readStream, writeStream){
// Here you can choose, for example 10x10 (thumbnail), etc.
gm(readStream).resize(600).stream('PNG').pipe(writeStream);
}
})]
});
and our basic Subscribe, on the same /lib/collection.js
if(Meteor.isClient) {
Meteor.subscribe('kaiStackExample');
}
Ok, at this point we have the GridFS and GM, to verify both
server console.
=> GraphicsMagick found
Client console.
kaiStackExample.find().fetch();
should return [];
Third SECURITY
kaiStackExample.allow({
insert:function(userId,doc){
//here we can do stuff like, only permit user with accounts insert on the collection
if(!Meteor.userId()){
return false;
}else{
return true
},
update:function(userId,doc){
if(userId === doc.authorId{
return true;
}else{
return false; // if user don't own the document can update it.
}
}
});
Four Template and Events
HTML markup
<template name="exampleKai">
Select File
<input type="file" id="fileExampleKai">
<button type="submit" id="buttonExampleKai">Click to upload</button>
</template>
Js Code
Template.exampleKai.events({
'click #buttonExampleKai':function(event,template){
event.preventDefault();
var file = $('#fileExampleKai').get(0).files[0];
fsFile = new FS.File(file);
fsFile.metadata = {
coolMetadata:"Yes You can add some metadata too"
}
if(file === undefined){
alert("Please upload a file to continue")
}else{
kaiStackExample.insert(fsFile,function(err,succes){
if(err){
console.log(err.reason);
}else{
console.log("ok we insert yeaaa")
}
});
}
}
});
Like i say this works for me, and i think its your best option for editing size,type,etc Take a look hope it help you
Even though Meteor is very good at keeping the client and server environments in sync, that doesn't mean it can do everything on the client that it can do on the server and vice versa. Converting images using ImageMagick would be one example of what you can only do on the server.
If I were to build something like this, I'd look into using CollectionFS for syncing files. They also have a section in the README that describes how to manipulate images before saving them, which seems to be just what you're after.
I'm trying to make a simple app with Phonegap, compiled with Adobe Phonegap builder. I've found and used the well documented example for using navigator.connection.type which is below, and to which I've added another line, to generate an alert box when the device is ready. It doesn't even get that far. I've had it at some points show that endless spinning circle, by moving this code from the head to the body of the page, but that is no help in the end. Testing on iOs and Android devices gives the same result, and the config.xml does include:-
<plugin name="NetworkStatus" value="CDVConnection" />
<plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager" />
Any help greatly appreciated.
// Wait for Cordova to load
//
document.addEventListener("deviceready", onDeviceReady, false);
// Cordova is loaded and it is now safe to make calls Cordova methods
//
function onDeviceReady() {
alert('Device is ready');
checkConnection();
}
function checkConnection() {
var networkState = navigator.connection.type;
var states = {};
states[Connection.UNKNOWN] = 'Unknown connection';
states[Connection.ETHERNET] = 'Ethernet connection';
states[Connection.WIFI] = 'WiFi connection';
states[Connection.CELL_2G] = 'Cell 2G connection';
states[Connection.CELL_3G] = 'Cell 3G connection';
states[Connection.CELL_4G] = 'Cell 4G connection';
states[Connection.CELL] = 'Cell generic connection';
states[Connection.NONE] = 'No network connection';
alert('Connection type: ' + states[networkState]);
}
</script>
You should also wait until all your scripts are loaded. Wrap everything in a onBodyLoad like so:
function onBodyLoad() {
// these are useful later in the app, might as well set early
window.isRipple = (window.tinyHippos != null);
window.isPhoneGap = /^file:\/{3}[^\/]/i.test(window.location.href);
window.isIOS = !window.isRipple && navigator.userAgent.match(/(ios|iphone|ipod|ipad)/gi) != null;
window.isAndroid = !window.isRipple && navigator.userAgent.match(/(android)/gi) != null;
// stuff I use for debugging in chrome
if (window.isPhoneGap) {
document.addEventListener("deviceready", onDeviceReady, false);
} else {
onDeviceReady();
}
}
And add to your body tag:
<body onload="onBodyLoad()">
And the rest of my code for additional references:
function checkOffLine(minutes) {
if (window.lastCheckTime == null) {
window.lastCheckTime = 0;
}
var currentTime = (new Date()).getTime();
if (currentTime < (window.lastCheckTime + minutes * 60000)) return;
window.lastCheckTime = currentTime;
// ios does not allow you to exit the application so just warn
// ios also require you to warn or your app get rejected
if (window.isIOS) {
navigator.notification.alert('This application may not function properly without an internet connection.');
} else {
navigator.notification.confirm(
'This application may not function properly without an internet connection. Continue working offline?', // message
function(button) // callback to invoke with index of button pressed
{
if (button == 1) {
navigator.app.exitApp();
}
},
'Warning', // title
'Exit,Continue' // buttonLabels
);
}
}
function checkConnection() {
// your check connection type code here or just use navigator.onLine
if (!navigator.onLine) {
// don't be annoying, only confirm for once every every 5 minutes
checkOffLine(5);
}
}
// initial phonegap deviceready handler
function onDeviceReady() {
console.log('Application started');
angular.bootstrap(document, ['assetsApp']);
if (window.isPhoneGap) {
document.addEventListener("offline", checkConnection, false);
checkConnection();
}
};
function onBodyLoad() {
// these are useful later in the app, might as well set early
window.isRipple = (window.tinyHippos != null);
window.isPhoneGap = /^file:\/{3}[^\/]/i.test(window.location.href);
window.isIOS = !window.isRipple && navigator.userAgent.match(/(ios|iphone|ipod|ipad)/gi) != null;
window.isAndroid = !window.isRipple && navigator.userAgent.match(/(android)/gi) != null;
// stuff I use for debugging in chrome
if (window.isPhoneGap) {
document.addEventListener("deviceready", onDeviceReady, false);
} else {
onDeviceReady();
}
}
I had the same issue and found I had to run "cordova build" and then the status was returned correctly.
BEWARE
When I run cordova build, it appears to take everything in my ~/app/www directory and overried everything in app/platforms/android/assets/www/
My "install process" is as follows:
cordova create app com.app "App"
cd app
cordova platform add android
cordova plugin add org.apache.cordova.network-information
cordova plugin add org.apache.cordova.camera
cordova plugin add org.apache.cordova.geolocation
cordova build
I can then do code changes in app/www and when happy, 'deploy' it using 'cordova build' (which seems to always copy the files to app/platforms/android/assets/www/.
If I add another plugin using: (for example)
cordova plugin add org.apache.cordova.file
then I need to run
cordova build
to have it work.
I hope this helps
(I am using cordova 3.3.1-0.1.2 )