diff --git a/src/simple-todos/step02/imports/ui/App.svelte b/src/simple-todos/step02/imports/ui/App.svelte index 3f1b70f..aa9e1a3 100644 --- a/src/simple-todos/step02/imports/ui/App.svelte +++ b/src/simple-todos/step02/imports/ui/App.svelte @@ -2,18 +2,25 @@ import Task from './Task.svelte'; import { TasksCollection } from '../api/TasksCollection'; - $m: tasks = TasksCollection.find({}).fetch() + let getTasks; + $m: getTasks = TasksCollection.find({}).fetchAsync()
-

Todo List

+

Todo List

- + {#await getTasks} +

Loading...

+ {:then tasks} + + {:catch error} +

{error.message}

+ {/await}
diff --git a/src/simple-todos/step02/server/main.js b/src/simple-todos/step02/server/main.js index cd5ce50..896720a 100644 --- a/src/simple-todos/step02/server/main.js +++ b/src/simple-todos/step02/server/main.js @@ -1,10 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { TasksCollection } from '/imports/api/TasksCollection'; -const insertTask = taskText => TasksCollection.insert({ text: taskText }); +const insertTask = async (taskText) => + await TasksCollection.insert({ text: taskText }); -Meteor.startup(() => { - if (TasksCollection.find().count() === 0) { +Meteor.startup(async () => { + if (await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step03/imports/ui/App.svelte b/src/simple-todos/step03/imports/ui/App.svelte index 64491ba..06f23bf 100644 --- a/src/simple-todos/step03/imports/ui/App.svelte +++ b/src/simple-todos/step03/imports/ui/App.svelte @@ -3,20 +3,27 @@ import Task from './Task.svelte'; import TaskForm from './TaskForm.svelte'; - $m: tasks = TasksCollection.find({}, { sort: { createdAt: -1 } }).fetch() + let getTasks; + $m: getTasks = TasksCollection.find({}, { sort: { createdAt: -1 } }).fetchAsync()
-

Todo List

+

Todo List

- + -
    - {#each tasks as task (task._id)} - - {/each} -
+ {#await getTasks} +

Loading...

+ {:then tasks} +
    + {#each tasks as task (task._id)} + + {/each} +
+ {:catch error} +

{error.message}

+ {/await}
diff --git a/src/simple-todos/step03/imports/ui/TaskForm.svelte b/src/simple-todos/step03/imports/ui/TaskForm.svelte index d0bdb47..7e51106 100644 --- a/src/simple-todos/step03/imports/ui/TaskForm.svelte +++ b/src/simple-todos/step03/imports/ui/TaskForm.svelte @@ -3,9 +3,9 @@ let newTask = ''; - const handleSubmit = () => { + const handleSubmit = async () => { // Insert a task into the collection - TasksCollection.insert({ + await TasksCollection.insertAsync({ text: newTask, createdAt: new Date(), // current time }); diff --git a/src/simple-todos/step03/server/main.js b/src/simple-todos/step03/server/main.js index cd5ce50..896720a 100644 --- a/src/simple-todos/step03/server/main.js +++ b/src/simple-todos/step03/server/main.js @@ -1,10 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { TasksCollection } from '/imports/api/TasksCollection'; -const insertTask = taskText => TasksCollection.insert({ text: taskText }); +const insertTask = async (taskText) => + await TasksCollection.insert({ text: taskText }); -Meteor.startup(() => { - if (TasksCollection.find().count() === 0) { +Meteor.startup(async () => { + if (await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step04/imports/ui/App.svelte b/src/simple-todos/step04/imports/ui/App.svelte index 64491ba..08c5124 100644 --- a/src/simple-todos/step04/imports/ui/App.svelte +++ b/src/simple-todos/step04/imports/ui/App.svelte @@ -3,7 +3,8 @@ import Task from './Task.svelte'; import TaskForm from './TaskForm.svelte'; - $m: tasks = TasksCollection.find({}, { sort: { createdAt: -1 } }).fetch() + let getTasks; + $m: getTasks = TasksCollection.find({}, { sort: { createdAt: -1 } }).fetchAsync() @@ -14,9 +15,16 @@ - + + {#await getTasks} +

Loading...

+ {:then tasks} + + {:catch error} +

{error.message}

+ {/await} diff --git a/src/simple-todos/step04/imports/ui/Task.svelte b/src/simple-todos/step04/imports/ui/Task.svelte index 3ad80ff..3fffb82 100644 --- a/src/simple-todos/step04/imports/ui/Task.svelte +++ b/src/simple-todos/step04/imports/ui/Task.svelte @@ -3,15 +3,15 @@ export let task; - const toggleChecked = () => { + const toggleChecked = async () => { // Set the checked property to the opposite of its current value - TasksCollection.update(task._id, { + await TasksCollection.updateAsync(task._id, { $set: { isChecked: !task.isChecked } }); }; - const deleteThisTask = () => { - TasksCollection.remove(task._id); + const deleteThisTask = async () => { + await TasksCollection.removeAsync(task._id); }; diff --git a/src/simple-todos/step04/imports/ui/TaskForm.svelte b/src/simple-todos/step04/imports/ui/TaskForm.svelte index d0bdb47..7e51106 100644 --- a/src/simple-todos/step04/imports/ui/TaskForm.svelte +++ b/src/simple-todos/step04/imports/ui/TaskForm.svelte @@ -3,9 +3,9 @@ let newTask = ''; - const handleSubmit = () => { + const handleSubmit = async () => { // Insert a task into the collection - TasksCollection.insert({ + await TasksCollection.insertAsync({ text: newTask, createdAt: new Date(), // current time }); diff --git a/src/simple-todos/step04/server/main.js b/src/simple-todos/step04/server/main.js index cd5ce50..896720a 100644 --- a/src/simple-todos/step04/server/main.js +++ b/src/simple-todos/step04/server/main.js @@ -1,10 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { TasksCollection } from '/imports/api/TasksCollection'; -const insertTask = taskText => TasksCollection.insert({ text: taskText }); +const insertTask = async (taskText) => + await TasksCollection.insert({ text: taskText }); -Meteor.startup(() => { - if (TasksCollection.find().count() === 0) { +Meteor.startup(async () => { + if (await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step05/imports/ui/App.svelte b/src/simple-todos/step05/imports/ui/App.svelte index c2d2f8a..b7d8ecf 100644 --- a/src/simple-todos/step05/imports/ui/App.svelte +++ b/src/simple-todos/step05/imports/ui/App.svelte @@ -3,7 +3,8 @@ import Task from './Task.svelte'; import TaskForm from './TaskForm.svelte'; - $m: tasks = TasksCollection.find({}, { sort: { createdAt: -1 } }).fetch() + let getTasks; + $m: getTasks = TasksCollection.find({}, { sort: { createdAt: -1 } }).fetchAsync() @@ -18,11 +19,16 @@
- -
    - {#each tasks as task (task._id)} - - {/each} -
+ {#await getTasks} +

Loading...

+ {:then tasks} +
    + {#each tasks as task (task._id)} + + {/each} +
+ {:catch error} +

{error.message}

+ {/await}
diff --git a/src/simple-todos/step05/imports/ui/Task.svelte b/src/simple-todos/step05/imports/ui/Task.svelte index 3ad80ff..3fffb82 100644 --- a/src/simple-todos/step05/imports/ui/Task.svelte +++ b/src/simple-todos/step05/imports/ui/Task.svelte @@ -3,15 +3,15 @@ export let task; - const toggleChecked = () => { + const toggleChecked = async () => { // Set the checked property to the opposite of its current value - TasksCollection.update(task._id, { + await TasksCollection.updateAsync(task._id, { $set: { isChecked: !task.isChecked } }); }; - const deleteThisTask = () => { - TasksCollection.remove(task._id); + const deleteThisTask = async () => { + await TasksCollection.removeAsync(task._id); }; diff --git a/src/simple-todos/step05/imports/ui/TaskForm.svelte b/src/simple-todos/step05/imports/ui/TaskForm.svelte index d0bdb47..7e51106 100644 --- a/src/simple-todos/step05/imports/ui/TaskForm.svelte +++ b/src/simple-todos/step05/imports/ui/TaskForm.svelte @@ -3,9 +3,9 @@ let newTask = ''; - const handleSubmit = () => { + const handleSubmit = async () => { // Insert a task into the collection - TasksCollection.insert({ + await TasksCollection.insertAsync({ text: newTask, createdAt: new Date(), // current time }); diff --git a/src/simple-todos/step05/server/main.js b/src/simple-todos/step05/server/main.js index cd5ce50..896720a 100644 --- a/src/simple-todos/step05/server/main.js +++ b/src/simple-todos/step05/server/main.js @@ -1,10 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { TasksCollection } from '/imports/api/TasksCollection'; -const insertTask = taskText => TasksCollection.insert({ text: taskText }); +const insertTask = async (taskText) => + await TasksCollection.insert({ text: taskText }); -Meteor.startup(() => { - if (TasksCollection.find().count() === 0) { +Meteor.startup(async () => { + if (await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step06/imports/ui/App.svelte b/src/simple-todos/step06/imports/ui/App.svelte index 0df1f71..c87260f 100644 --- a/src/simple-todos/step06/imports/ui/App.svelte +++ b/src/simple-todos/step06/imports/ui/App.svelte @@ -6,21 +6,19 @@ let hideCompleted = false; const hideCompletedFilter = { isChecked: { $ne: true } }; - - let incompleteCount; - let pendingTasksTitle = ''; - let tasks = []; + let getTasks; + let getCount; $m: { - tasks = TasksCollection.find(hideCompleted ? hideCompletedFilter : {}, { + getTasks = TasksCollection.find(hideCompleted ? hideCompletedFilter : {}, { sort: { createdAt: -1 }, - }).fetch(); - - incompleteCount = TasksCollection.find(hideCompletedFilter).count(); + }).fetchAsync(); - pendingTasksTitle = `${incompleteCount ? ` (${incompleteCount})` : ''}`; + getCount = TasksCollection.find(hideCompletedFilter).countAsync(); } + const pendingTitle = (count) => `${count ? ` (${count})` : ''}`; + const setHideCompleted = (value) => { hideCompleted = value; }; @@ -30,7 +28,11 @@
-

📝️ To Do List {pendingTasksTitle}

+ {#await getCount} +

📝️ To Do List (...)

+ {:then count} +

📝️ To Do List {pendingTitle(count)}

+ {/await}
@@ -42,10 +44,16 @@ {hideCompleted ? 'Show All' : 'Hide Completed'} - + {#await getTasks} +

Loading...

+ {:then tasks} + + {:catch error} +

{error.message}

+ {/await} diff --git a/src/simple-todos/step06/imports/ui/Task.svelte b/src/simple-todos/step06/imports/ui/Task.svelte index 3ad80ff..43911f6 100644 --- a/src/simple-todos/step06/imports/ui/Task.svelte +++ b/src/simple-todos/step06/imports/ui/Task.svelte @@ -3,24 +3,24 @@ export let task; - const toggleChecked = () => { + const toggleChecked = async () => { // Set the checked property to the opposite of its current value - TasksCollection.update(task._id, { + await TasksCollection.updateAsync(task._id, { $set: { isChecked: !task.isChecked } }); }; - const deleteThisTask = () => { - TasksCollection.remove(task._id); + const deleteThisTask = async () => { + await TasksCollection.removeAsync(task._id); };
  • { task.text } diff --git a/src/simple-todos/step06/imports/ui/TaskForm.svelte b/src/simple-todos/step06/imports/ui/TaskForm.svelte index d0bdb47..0f1bc86 100644 --- a/src/simple-todos/step06/imports/ui/TaskForm.svelte +++ b/src/simple-todos/step06/imports/ui/TaskForm.svelte @@ -1,18 +1,18 @@
    diff --git a/src/simple-todos/step06/server/main.js b/src/simple-todos/step06/server/main.js index cd5ce50..896720a 100644 --- a/src/simple-todos/step06/server/main.js +++ b/src/simple-todos/step06/server/main.js @@ -1,10 +1,11 @@ import { Meteor } from 'meteor/meteor'; import { TasksCollection } from '/imports/api/TasksCollection'; -const insertTask = taskText => TasksCollection.insert({ text: taskText }); +const insertTask = async (taskText) => + await TasksCollection.insert({ text: taskText }); -Meteor.startup(() => { - if (TasksCollection.find().count() === 0) { +Meteor.startup(async () => { + if (await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step07/imports/ui/App.svelte b/src/simple-todos/step07/imports/ui/App.svelte index 1f16261..4b4fdf3 100644 --- a/src/simple-todos/step07/imports/ui/App.svelte +++ b/src/simple-todos/step07/imports/ui/App.svelte @@ -10,9 +10,8 @@ const hideCompletedFilter = { isChecked: { $ne: true } }; - let incompleteCount; - let pendingTasksTitle = ''; - let tasks = []; + let getTasks; + let getCount; let user = null; $m: { @@ -22,22 +21,19 @@ const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; - tasks = user + getTasks = user ? TasksCollection.find( hideCompleted ? pendingOnlyFilter : userFilter, { sort: { createdAt: -1 } } - ).fetch() + ).fetchAsync() : []; - incompleteCount = user - ? TasksCollection.find(pendingOnlyFilter).count() + getCount = user + ? TasksCollection.find(pendingOnlyFilter).countAsync() : 0; - pendingTasksTitle = `${ - incompleteCount ? ` (${incompleteCount})` : '' - }`; } - + const pendingTitle = (count) => `${count ? ` (${count})` : ''}`; const setHideCompleted = value => { hideCompleted = value; }; @@ -49,7 +45,11 @@
    -

    📝️ To Do List {pendingTasksTitle}

    + {#await getCount} +

    📝️ To Do List (...)

    + {:then count} +

    📝️ To Do List {pendingTitle(count)}

    + {/await}
    @@ -67,11 +67,17 @@ {hideCompleted ? 'Show All' : 'Hide Completed'} -
      - {#each tasks as task (task._id)} - - {/each} -
    + {#await getTasks} +

    Loading...

    + {:then tasks} +
      + {#each tasks as task (task._id)} + + {/each} +
    + {:catch error} +

    {error.message}

    + {/await} {:else} {/if} diff --git a/src/simple-todos/step07/imports/ui/Task.svelte b/src/simple-todos/step07/imports/ui/Task.svelte index 3ad80ff..43911f6 100644 --- a/src/simple-todos/step07/imports/ui/Task.svelte +++ b/src/simple-todos/step07/imports/ui/Task.svelte @@ -3,24 +3,24 @@ export let task; - const toggleChecked = () => { + const toggleChecked = async () => { // Set the checked property to the opposite of its current value - TasksCollection.update(task._id, { + await TasksCollection.updateAsync(task._id, { $set: { isChecked: !task.isChecked } }); }; - const deleteThisTask = () => { - TasksCollection.remove(task._id); + const deleteThisTask = async () => { + await TasksCollection.removeAsync(task._id); };
  • { task.text } diff --git a/src/simple-todos/step07/imports/ui/TaskForm.svelte b/src/simple-todos/step07/imports/ui/TaskForm.svelte index 2739f49..efe463e 100644 --- a/src/simple-todos/step07/imports/ui/TaskForm.svelte +++ b/src/simple-todos/step07/imports/ui/TaskForm.svelte @@ -4,9 +4,9 @@ export let user = null; let newTask = ''; - const handleSubmit = () => { + const handleSubmit = async () => { // Insert a task into the collection - TasksCollection.insert({ + await TasksCollection.insertAsync({ text: newTask, createdAt: new Date(), // current time userId: user._id, diff --git a/src/simple-todos/step07/server/main.js b/src/simple-todos/step07/server/main.js index cea2c26..b317967 100644 --- a/src/simple-todos/step07/server/main.js +++ b/src/simple-todos/step07/server/main.js @@ -2,8 +2,8 @@ import { Meteor } from 'meteor/meteor'; import { Accounts } from 'meteor/accounts-base'; import { TasksCollection } from '/imports/api/TasksCollection'; -const insertTask = (taskText, user) => - TasksCollection.insert({ +const insertTask = async (taskText, user) => + await TasksCollection.insertAsync({ text: taskText, userId: user._id, createdAt: new Date(), @@ -12,7 +12,7 @@ const insertTask = (taskText, user) => const SEED_USERNAME = 'meteorite'; const SEED_PASSWORD = 'password'; -Meteor.startup(() => { +Meteor.startup(async () => { if (!Accounts.findUserByUsername(SEED_USERNAME)) { Accounts.createUser({ username: SEED_USERNAME, @@ -22,7 +22,7 @@ Meteor.startup(() => { const user = Accounts.findUserByUsername(SEED_USERNAME); - if (TasksCollection.find().count() === 0) { + if ( await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step08/imports/api/tasksMethods.js b/src/simple-todos/step08/imports/api/tasksMethods.js index 51b06d7..5d2c6e4 100644 --- a/src/simple-todos/step08/imports/api/tasksMethods.js +++ b/src/simple-todos/step08/imports/api/tasksMethods.js @@ -3,31 +3,31 @@ import { check } from 'meteor/check'; import { TasksCollection } from '../db/TasksCollection'; Meteor.methods({ - 'tasks.insert'(text) { + async 'tasks.insert'(text) { check(text, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - TasksCollection.insert({ + await TasksCollection.insertAsync({ text, createdAt: new Date(), userId: this.userId, }); }, - 'tasks.remove'(taskId) { + async 'tasks.remove'(taskId) { check(taskId, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - TasksCollection.remove(taskId); + await TasksCollection.removeAsync(taskId); }, - 'tasks.setIsChecked'(taskId, isChecked) { + async 'tasks.setIsChecked'(taskId, isChecked) { check(taskId, String); check(isChecked, Boolean); @@ -35,7 +35,7 @@ Meteor.methods({ throw new Meteor.Error('Not authorized.'); } - TasksCollection.update(taskId, { + await TasksCollection.updateAsync(taskId, { $set: { isChecked, }, diff --git a/src/simple-todos/step08/imports/ui/App.svelte b/src/simple-todos/step08/imports/ui/App.svelte index fe7f014..5626dca 100644 --- a/src/simple-todos/step08/imports/ui/App.svelte +++ b/src/simple-todos/step08/imports/ui/App.svelte @@ -10,9 +10,8 @@ const hideCompletedFilter = { isChecked: { $ne: true } }; - let incompleteCount; - let pendingTasksTitle = ''; - let tasks = []; + let getTasks; + let getCount; let user = null; $m: { @@ -22,22 +21,19 @@ const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; - tasks = user + getTasks = user ? TasksCollection.find( - hideCompleted ? pendingOnlyFilter : userFilter, - { sort: { createdAt: -1 } } - ).fetch() + hideCompleted ? pendingOnlyFilter : userFilter, + { sort: { createdAt: -1 } } + ).fetchAsync() : []; - incompleteCount = user - ? TasksCollection.find(pendingOnlyFilter).count() - : 0; + getCount = user + ? TasksCollection.find(pendingOnlyFilter).countAsync() + : 0; - pendingTasksTitle = `${ - incompleteCount ? ` (${incompleteCount})` : '' - }`; } - + const pendingTitle = (count) => `${count ? ` (${count})` : ''}`; const setHideCompleted = value => { hideCompleted = value; }; @@ -49,7 +45,11 @@
    -

    📝️ To Do List {pendingTasksTitle}

    + {#await getCount} +

    📝️ To Do List (...)

    + {:then count} +

    📝️ To Do List {pendingTitle(count)}

    + {/await}
    @@ -60,18 +60,24 @@ {user.username} 🚪 - +
    -
      - {#each tasks as task (task._id)} - - {/each} -
    + {#await getTasks} +

    Loading...

    + {:then tasks} +
      + {#each tasks as task (task._id)} + + {/each} +
    + {:catch error} +

    {error.message}

    + {/await} {:else} {/if} diff --git a/src/simple-todos/step08/imports/ui/Task.svelte b/src/simple-todos/step08/imports/ui/Task.svelte index 7d0a4ad..e877fca 100644 --- a/src/simple-todos/step08/imports/ui/Task.svelte +++ b/src/simple-todos/step08/imports/ui/Task.svelte @@ -5,7 +5,8 @@ Meteor.call('tasks.setIsChecked', task._id, !task.isChecked); - const deleteThisTask = () => Meteor.call('tasks.remove', task._id); + const deleteThisTask = () => + Meteor.call('tasks.remove', task._id);
  • diff --git a/src/simple-todos/step08/server/main.js b/src/simple-todos/step08/server/main.js index 4a148bb..99c4751 100644 --- a/src/simple-todos/step08/server/main.js +++ b/src/simple-todos/step08/server/main.js @@ -3,8 +3,8 @@ import { Accounts } from 'meteor/accounts-base'; import { TasksCollection } from '/imports/db/TasksCollection'; import '/imports/api/tasksMethods'; -const insertTask = (taskText, user) => - TasksCollection.insert({ +const insertTask = async (taskText, user) => + await TasksCollection.insertAsync({ text: taskText, userId: user._id, createdAt: new Date(), @@ -13,7 +13,7 @@ const insertTask = (taskText, user) => const SEED_USERNAME = 'meteorite'; const SEED_PASSWORD = 'password'; -Meteor.startup(() => { +Meteor.startup(async () => { if (!Accounts.findUserByUsername(SEED_USERNAME)) { Accounts.createUser({ username: SEED_USERNAME, @@ -23,7 +23,7 @@ Meteor.startup(() => { const user = Accounts.findUserByUsername(SEED_USERNAME); - if (TasksCollection.find().count() === 0) { + if ( await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step09/imports/api/tasksMethods.js b/src/simple-todos/step09/imports/api/tasksMethods.js index b1ddc18..10f8aa6 100644 --- a/src/simple-todos/step09/imports/api/tasksMethods.js +++ b/src/simple-todos/step09/imports/api/tasksMethods.js @@ -3,37 +3,37 @@ import { check } from 'meteor/check'; import { TasksCollection } from '../db/TasksCollection'; Meteor.methods({ - 'tasks.insert'(text) { + async 'tasks.insert'(text) { check(text, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - TasksCollection.insert({ + await TasksCollection.insertAsync({ text, createdAt: new Date(), userId: this.userId, }); }, - 'tasks.remove'(taskId) { + async 'tasks.remove'(taskId) { check(taskId, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.remove(taskId); + await TasksCollection.remove(taskId); }, - 'tasks.setIsChecked'(taskId, isChecked) { + async 'tasks.setIsChecked'(taskId, isChecked) { check(taskId, String); check(isChecked, Boolean); @@ -41,13 +41,13 @@ Meteor.methods({ throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.update(taskId, { + await TasksCollection.updateAsync(taskId, { $set: { isChecked, }, diff --git a/src/simple-todos/step09/imports/ui/App.svelte b/src/simple-todos/step09/imports/ui/App.svelte index 0b52de6..a483e0b 100644 --- a/src/simple-todos/step09/imports/ui/App.svelte +++ b/src/simple-todos/step09/imports/ui/App.svelte @@ -10,9 +10,8 @@ const hideCompletedFilter = { isChecked: { $ne: true } }; - let incompleteCount; - let pendingTasksTitle = ''; - let tasks = []; + let getTasks; + let getCount; let user = null; let isLoading = true; @@ -22,24 +21,25 @@ if (user) { - isLoading = !handler.ready(); + isLoading = !handler.ready(); - const userFilter = { userId: user._id }; - const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; + const userFilter = { userId: user._id }; + const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; - tasks = TasksCollection.find( - hideCompleted ? pendingOnlyFilter : userFilter, - { sort: { createdAt: -1 } } - ).fetch(); + getTasks = user + ? TasksCollection.find( + hideCompleted ? pendingOnlyFilter : userFilter, + { sort: { createdAt: -1 } } + ).fetchAsync() + : []; - incompleteCount = TasksCollection.find(pendingOnlyFilter).count(); - - pendingTasksTitle = `${ - incompleteCount ? ` (${incompleteCount})` : '' - }`; + getCount = user + ? TasksCollection.find(pendingOnlyFilter).countAsync() + : 0; } } + const pendingTitle = (count) => `${count ? ` (${count})` : ''}`; const setHideCompleted = value => { hideCompleted = value; @@ -52,7 +52,11 @@
    -

    📝️ To Do List {pendingTasksTitle}

    + {#await getCount} +

    📝️ To Do List (...)

    + {:then count} +

    📝️ To Do List {pendingTitle(count)}

    + {/await}
    @@ -75,11 +79,16 @@
    loading...
    {/if} -
      - {#each tasks as task (task._id)} - - {/each} -
    + {#await getTasks} + {:then tasks} +
      + {#each tasks as task (task._id)} + + {/each} +
    + {:catch error} +

    {error.message}

    + {/await} {:else} {/if} diff --git a/src/simple-todos/step09/server/main.js b/src/simple-todos/step09/server/main.js index 39d8744..7a52216 100644 --- a/src/simple-todos/step09/server/main.js +++ b/src/simple-todos/step09/server/main.js @@ -4,8 +4,8 @@ import { TasksCollection } from '/imports/db/TasksCollection'; import '/imports/api/tasksMethods'; import '/imports/api/tasksPublications'; -const insertTask = (taskText, user) => - TasksCollection.insert({ +const insertTask = async (taskText, user) => + await TasksCollection.insertAsync({ text: taskText, userId: user._id, createdAt: new Date(), @@ -14,7 +14,7 @@ const insertTask = (taskText, user) => const SEED_USERNAME = 'meteorite'; const SEED_PASSWORD = 'password'; -Meteor.startup(() => { +Meteor.startup(async () => { if (!Accounts.findUserByUsername(SEED_USERNAME)) { Accounts.createUser({ username: SEED_USERNAME, @@ -24,7 +24,7 @@ Meteor.startup(() => { const user = Accounts.findUserByUsername(SEED_USERNAME); - if (TasksCollection.find().count() === 0) { + if ( await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step10/imports/api/tasksMethods.js b/src/simple-todos/step10/imports/api/tasksMethods.js index b1ddc18..10f8aa6 100644 --- a/src/simple-todos/step10/imports/api/tasksMethods.js +++ b/src/simple-todos/step10/imports/api/tasksMethods.js @@ -3,37 +3,37 @@ import { check } from 'meteor/check'; import { TasksCollection } from '../db/TasksCollection'; Meteor.methods({ - 'tasks.insert'(text) { + async 'tasks.insert'(text) { check(text, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - TasksCollection.insert({ + await TasksCollection.insertAsync({ text, createdAt: new Date(), userId: this.userId, }); }, - 'tasks.remove'(taskId) { + async 'tasks.remove'(taskId) { check(taskId, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.remove(taskId); + await TasksCollection.remove(taskId); }, - 'tasks.setIsChecked'(taskId, isChecked) { + async 'tasks.setIsChecked'(taskId, isChecked) { check(taskId, String); check(isChecked, Boolean); @@ -41,13 +41,13 @@ Meteor.methods({ throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.update(taskId, { + await TasksCollection.updateAsync(taskId, { $set: { isChecked, }, diff --git a/src/simple-todos/step10/imports/ui/App.svelte b/src/simple-todos/step10/imports/ui/App.svelte index 0b52de6..a483e0b 100644 --- a/src/simple-todos/step10/imports/ui/App.svelte +++ b/src/simple-todos/step10/imports/ui/App.svelte @@ -10,9 +10,8 @@ const hideCompletedFilter = { isChecked: { $ne: true } }; - let incompleteCount; - let pendingTasksTitle = ''; - let tasks = []; + let getTasks; + let getCount; let user = null; let isLoading = true; @@ -22,24 +21,25 @@ if (user) { - isLoading = !handler.ready(); + isLoading = !handler.ready(); - const userFilter = { userId: user._id }; - const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; + const userFilter = { userId: user._id }; + const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; - tasks = TasksCollection.find( - hideCompleted ? pendingOnlyFilter : userFilter, - { sort: { createdAt: -1 } } - ).fetch(); + getTasks = user + ? TasksCollection.find( + hideCompleted ? pendingOnlyFilter : userFilter, + { sort: { createdAt: -1 } } + ).fetchAsync() + : []; - incompleteCount = TasksCollection.find(pendingOnlyFilter).count(); - - pendingTasksTitle = `${ - incompleteCount ? ` (${incompleteCount})` : '' - }`; + getCount = user + ? TasksCollection.find(pendingOnlyFilter).countAsync() + : 0; } } + const pendingTitle = (count) => `${count ? ` (${count})` : ''}`; const setHideCompleted = value => { hideCompleted = value; @@ -52,7 +52,11 @@
    -

    📝️ To Do List {pendingTasksTitle}

    + {#await getCount} +

    📝️ To Do List (...)

    + {:then count} +

    📝️ To Do List {pendingTitle(count)}

    + {/await}
    @@ -75,11 +79,16 @@
    loading...
    {/if} -
      - {#each tasks as task (task._id)} - - {/each} -
    + {#await getTasks} + {:then tasks} +
      + {#each tasks as task (task._id)} + + {/each} +
    + {:catch error} +

    {error.message}

    + {/await} {:else} {/if} diff --git a/src/simple-todos/step10/server/main.js b/src/simple-todos/step10/server/main.js index 39d8744..7a52216 100644 --- a/src/simple-todos/step10/server/main.js +++ b/src/simple-todos/step10/server/main.js @@ -4,8 +4,8 @@ import { TasksCollection } from '/imports/db/TasksCollection'; import '/imports/api/tasksMethods'; import '/imports/api/tasksPublications'; -const insertTask = (taskText, user) => - TasksCollection.insert({ +const insertTask = async (taskText, user) => + await TasksCollection.insertAsync({ text: taskText, userId: user._id, createdAt: new Date(), @@ -14,7 +14,7 @@ const insertTask = (taskText, user) => const SEED_USERNAME = 'meteorite'; const SEED_PASSWORD = 'password'; -Meteor.startup(() => { +Meteor.startup(async () => { if (!Accounts.findUserByUsername(SEED_USERNAME)) { Accounts.createUser({ username: SEED_USERNAME, @@ -24,7 +24,7 @@ Meteor.startup(() => { const user = Accounts.findUserByUsername(SEED_USERNAME); - if (TasksCollection.find().count() === 0) { + if ( await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step11/imports/api/tasksMethods.js b/src/simple-todos/step11/imports/api/tasksMethods.js index b1ddc18..10f8aa6 100644 --- a/src/simple-todos/step11/imports/api/tasksMethods.js +++ b/src/simple-todos/step11/imports/api/tasksMethods.js @@ -3,37 +3,37 @@ import { check } from 'meteor/check'; import { TasksCollection } from '../db/TasksCollection'; Meteor.methods({ - 'tasks.insert'(text) { + async 'tasks.insert'(text) { check(text, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - TasksCollection.insert({ + await TasksCollection.insertAsync({ text, createdAt: new Date(), userId: this.userId, }); }, - 'tasks.remove'(taskId) { + async 'tasks.remove'(taskId) { check(taskId, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.remove(taskId); + await TasksCollection.remove(taskId); }, - 'tasks.setIsChecked'(taskId, isChecked) { + async 'tasks.setIsChecked'(taskId, isChecked) { check(taskId, String); check(isChecked, Boolean); @@ -41,13 +41,13 @@ Meteor.methods({ throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.update(taskId, { + await TasksCollection.updateAsync(taskId, { $set: { isChecked, }, diff --git a/src/simple-todos/step11/imports/api/tasksMethods.tests.js b/src/simple-todos/step11/imports/api/tasksMethods.tests.js index 953269b..e382e79 100644 --- a/src/simple-todos/step11/imports/api/tasksMethods.tests.js +++ b/src/simple-todos/step11/imports/api/tasksMethods.tests.js @@ -11,53 +11,53 @@ if (Meteor.isServer) { const userId = Random.id(); let taskId; - beforeEach(() => { - TasksCollection.remove({}); - taskId = TasksCollection.insert({ + beforeEach(async () => { + await TasksCollection.removeAsync({}); + taskId = await TasksCollection.insertAsync({ text: 'Test Task', createdAt: new Date(), userId, }); }); - it('can delete owned task', () => { + it('can delete owned task', async () => { mockMethodCall('tasks.remove', taskId, { context: { userId } }); - assert.equal(TasksCollection.find().count(), 0); + assert.equal(await TasksCollection.find().countAsync(), 0); }); - it("can't delete task without an user authenticated", () => { + it("can't delete task without an user authenticated", async () => { const fn = () => mockMethodCall('tasks.remove', taskId); assert.throw(fn, /Not authorized/); - assert.equal(TasksCollection.find().count(), 1); + assert.equal(await TasksCollection.find().countAsync(), 1); }); - it("can't delete task from another owner", () => { + it("can't delete task from another owner", async () => { const fn = () => mockMethodCall('tasks.remove', taskId, { context: { userId: 'somebody-else-id' }, }); assert.throw(fn, /Access denied/); - assert.equal(TasksCollection.find().count(), 1); + assert.equal(await TasksCollection.find().countAsync(), 1); }); - it('can change the status of a task', () => { - const originalTask = TasksCollection.findOne(taskId); + it('can change the status of a task', async () => { + const originalTask = await TasksCollection.findOneAsync(taskId); mockMethodCall('tasks.setIsChecked', taskId, !originalTask.isChecked, { context: { userId }, }); - const updatedTask = TasksCollection.findOne(taskId); + const updatedTask = await TasksCollection.findOneAsync(taskId); assert.notEqual(updatedTask.isChecked, originalTask.isChecked); }); - it('can insert new tasks', () => { + it('can insert new tasks', async () => { const text = 'New Task'; mockMethodCall('tasks.insert', text, { context: { userId }, }); - const tasks = TasksCollection.find({}).fetch(); + const tasks = await TasksCollection.find({}).fetchAsync(); assert.equal(tasks.length, 2); assert.isTrue(tasks.some(task => task.text === text)); }); diff --git a/src/simple-todos/step11/imports/ui/App.svelte b/src/simple-todos/step11/imports/ui/App.svelte index 0b52de6..ec2bb1c 100644 --- a/src/simple-todos/step11/imports/ui/App.svelte +++ b/src/simple-todos/step11/imports/ui/App.svelte @@ -10,9 +10,8 @@ const hideCompletedFilter = { isChecked: { $ne: true } }; - let incompleteCount; - let pendingTasksTitle = ''; - let tasks = []; + let getTasks; + let getCount; let user = null; let isLoading = true; @@ -22,24 +21,25 @@ if (user) { - isLoading = !handler.ready(); + isLoading = !handler.ready(); - const userFilter = { userId: user._id }; - const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; + const userFilter = { userId: user._id }; + const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; - tasks = TasksCollection.find( - hideCompleted ? pendingOnlyFilter : userFilter, - { sort: { createdAt: -1 } } - ).fetch(); + getTasks = user + ? TasksCollection.find( + hideCompleted ? pendingOnlyFilter : userFilter, + { sort: { createdAt: -1 } } + ).fetchAsync() + : []; - incompleteCount = TasksCollection.find(pendingOnlyFilter).count(); - - pendingTasksTitle = `${ - incompleteCount ? ` (${incompleteCount})` : '' - }`; + getCount = user + ? TasksCollection.find(pendingOnlyFilter).countAsync() + : 0; } } + const pendingTitle = (count) => `${count ? ` (${count})` : ''}`; const setHideCompleted = value => { hideCompleted = value; @@ -52,7 +52,11 @@
    -

    📝️ To Do List {pendingTasksTitle}

    + {#await getCount} +

    📝️ To Do List (...)

    + {:then count} +

    📝️ To Do List {pendingTitle(count)}

    + {/await}
    @@ -63,7 +67,7 @@ {user.username} 🚪 - +
    diff --git a/src/simple-todos/step11/server/main.js b/src/simple-todos/step11/server/main.js index 39d8744..7a52216 100644 --- a/src/simple-todos/step11/server/main.js +++ b/src/simple-todos/step11/server/main.js @@ -4,8 +4,8 @@ import { TasksCollection } from '/imports/db/TasksCollection'; import '/imports/api/tasksMethods'; import '/imports/api/tasksPublications'; -const insertTask = (taskText, user) => - TasksCollection.insert({ +const insertTask = async (taskText, user) => + await TasksCollection.insertAsync({ text: taskText, userId: user._id, createdAt: new Date(), @@ -14,7 +14,7 @@ const insertTask = (taskText, user) => const SEED_USERNAME = 'meteorite'; const SEED_PASSWORD = 'password'; -Meteor.startup(() => { +Meteor.startup(async () => { if (!Accounts.findUserByUsername(SEED_USERNAME)) { Accounts.createUser({ username: SEED_USERNAME, @@ -24,7 +24,7 @@ Meteor.startup(() => { const user = Accounts.findUserByUsername(SEED_USERNAME); - if (TasksCollection.find().count() === 0) { + if ( await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/src/simple-todos/step12/imports/api/tasksMethods.js b/src/simple-todos/step12/imports/api/tasksMethods.js index b1ddc18..10f8aa6 100644 --- a/src/simple-todos/step12/imports/api/tasksMethods.js +++ b/src/simple-todos/step12/imports/api/tasksMethods.js @@ -3,37 +3,37 @@ import { check } from 'meteor/check'; import { TasksCollection } from '../db/TasksCollection'; Meteor.methods({ - 'tasks.insert'(text) { + async 'tasks.insert'(text) { check(text, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - TasksCollection.insert({ + await TasksCollection.insertAsync({ text, createdAt: new Date(), userId: this.userId, }); }, - 'tasks.remove'(taskId) { + async 'tasks.remove'(taskId) { check(taskId, String); if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.remove(taskId); + await TasksCollection.remove(taskId); }, - 'tasks.setIsChecked'(taskId, isChecked) { + async 'tasks.setIsChecked'(taskId, isChecked) { check(taskId, String); check(isChecked, Boolean); @@ -41,13 +41,13 @@ Meteor.methods({ throw new Meteor.Error('Not authorized.'); } - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); if (!task) { throw new Meteor.Error('Access denied.'); } - TasksCollection.update(taskId, { + await TasksCollection.updateAsync(taskId, { $set: { isChecked, }, diff --git a/src/simple-todos/step12/imports/api/tasksMethods.tests.js b/src/simple-todos/step12/imports/api/tasksMethods.tests.js index 953269b..e382e79 100644 --- a/src/simple-todos/step12/imports/api/tasksMethods.tests.js +++ b/src/simple-todos/step12/imports/api/tasksMethods.tests.js @@ -11,53 +11,53 @@ if (Meteor.isServer) { const userId = Random.id(); let taskId; - beforeEach(() => { - TasksCollection.remove({}); - taskId = TasksCollection.insert({ + beforeEach(async () => { + await TasksCollection.removeAsync({}); + taskId = await TasksCollection.insertAsync({ text: 'Test Task', createdAt: new Date(), userId, }); }); - it('can delete owned task', () => { + it('can delete owned task', async () => { mockMethodCall('tasks.remove', taskId, { context: { userId } }); - assert.equal(TasksCollection.find().count(), 0); + assert.equal(await TasksCollection.find().countAsync(), 0); }); - it("can't delete task without an user authenticated", () => { + it("can't delete task without an user authenticated", async () => { const fn = () => mockMethodCall('tasks.remove', taskId); assert.throw(fn, /Not authorized/); - assert.equal(TasksCollection.find().count(), 1); + assert.equal(await TasksCollection.find().countAsync(), 1); }); - it("can't delete task from another owner", () => { + it("can't delete task from another owner", async () => { const fn = () => mockMethodCall('tasks.remove', taskId, { context: { userId: 'somebody-else-id' }, }); assert.throw(fn, /Access denied/); - assert.equal(TasksCollection.find().count(), 1); + assert.equal(await TasksCollection.find().countAsync(), 1); }); - it('can change the status of a task', () => { - const originalTask = TasksCollection.findOne(taskId); + it('can change the status of a task', async () => { + const originalTask = await TasksCollection.findOneAsync(taskId); mockMethodCall('tasks.setIsChecked', taskId, !originalTask.isChecked, { context: { userId }, }); - const updatedTask = TasksCollection.findOne(taskId); + const updatedTask = await TasksCollection.findOneAsync(taskId); assert.notEqual(updatedTask.isChecked, originalTask.isChecked); }); - it('can insert new tasks', () => { + it('can insert new tasks', async () => { const text = 'New Task'; mockMethodCall('tasks.insert', text, { context: { userId }, }); - const tasks = TasksCollection.find({}).fetch(); + const tasks = await TasksCollection.find({}).fetchAsync(); assert.equal(tasks.length, 2); assert.isTrue(tasks.some(task => task.text === text)); }); diff --git a/src/simple-todos/step12/imports/ui/App.svelte b/src/simple-todos/step12/imports/ui/App.svelte index 0b52de6..ec2bb1c 100644 --- a/src/simple-todos/step12/imports/ui/App.svelte +++ b/src/simple-todos/step12/imports/ui/App.svelte @@ -10,9 +10,8 @@ const hideCompletedFilter = { isChecked: { $ne: true } }; - let incompleteCount; - let pendingTasksTitle = ''; - let tasks = []; + let getTasks; + let getCount; let user = null; let isLoading = true; @@ -22,24 +21,25 @@ if (user) { - isLoading = !handler.ready(); + isLoading = !handler.ready(); - const userFilter = { userId: user._id }; - const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; + const userFilter = { userId: user._id }; + const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilter }; - tasks = TasksCollection.find( - hideCompleted ? pendingOnlyFilter : userFilter, - { sort: { createdAt: -1 } } - ).fetch(); + getTasks = user + ? TasksCollection.find( + hideCompleted ? pendingOnlyFilter : userFilter, + { sort: { createdAt: -1 } } + ).fetchAsync() + : []; - incompleteCount = TasksCollection.find(pendingOnlyFilter).count(); - - pendingTasksTitle = `${ - incompleteCount ? ` (${incompleteCount})` : '' - }`; + getCount = user + ? TasksCollection.find(pendingOnlyFilter).countAsync() + : 0; } } + const pendingTitle = (count) => `${count ? ` (${count})` : ''}`; const setHideCompleted = value => { hideCompleted = value; @@ -52,7 +52,11 @@
    -

    📝️ To Do List {pendingTasksTitle}

    + {#await getCount} +

    📝️ To Do List (...)

    + {:then count} +

    📝️ To Do List {pendingTitle(count)}

    + {/await}
    @@ -63,7 +67,7 @@ {user.username} 🚪 - +
    diff --git a/src/simple-todos/step12/server/main.js b/src/simple-todos/step12/server/main.js index 39d8744..7a52216 100644 --- a/src/simple-todos/step12/server/main.js +++ b/src/simple-todos/step12/server/main.js @@ -4,8 +4,8 @@ import { TasksCollection } from '/imports/db/TasksCollection'; import '/imports/api/tasksMethods'; import '/imports/api/tasksPublications'; -const insertTask = (taskText, user) => - TasksCollection.insert({ +const insertTask = async (taskText, user) => + await TasksCollection.insertAsync({ text: taskText, userId: user._id, createdAt: new Date(), @@ -14,7 +14,7 @@ const insertTask = (taskText, user) => const SEED_USERNAME = 'meteorite'; const SEED_PASSWORD = 'password'; -Meteor.startup(() => { +Meteor.startup(async () => { if (!Accounts.findUserByUsername(SEED_USERNAME)) { Accounts.createUser({ username: SEED_USERNAME, @@ -24,7 +24,7 @@ Meteor.startup(() => { const user = Accounts.findUserByUsername(SEED_USERNAME); - if (TasksCollection.find().count() === 0) { + if ( await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', diff --git a/tutorial/changelog.md b/tutorial/changelog.md index fdd9b88..06b3d39 100644 --- a/tutorial/changelog.md +++ b/tutorial/changelog.md @@ -1,6 +1,8 @@ --- title: Changelog --- +v1.2 - 05/09/2022 +- Adjusted tutorial to use Mongo Async API. v1.1 - 16/05/2022 - Tutorial Review. diff --git a/tutorial/simple-todos/02-collections.md b/tutorial/simple-todos/02-collections.md index c21c51b..9062be2 100644 --- a/tutorial/simple-todos/02-collections.md +++ b/tutorial/simple-todos/02-collections.md @@ -37,10 +37,11 @@ You don't need to keep the old content of `server/main.js`. import { Meteor } from 'meteor/meteor'; import { TasksCollection } from '/imports/api/TasksCollection'; -const insertTask = taskText => TasksCollection.insert({ text: taskText }); - -Meteor.startup(() => { - if (TasksCollection.find().count() === 0) { +const insertTask = async (taskText) => + await TasksCollection.insert({ text: taskText }); + +Meteor.startup(async () => { + if (await TasksCollection.find().countAsync() === 0) { [ 'First Task', 'Second Task', @@ -48,10 +49,11 @@ Meteor.startup(() => { 'Fourth Task', 'Fifth Task', 'Sixth Task', - 'Seventh Task' - ].forEach(insertTask) + 'Seventh Task', + ].forEach(insertTask); } }); + ``` So you are importing the `TasksCollection` and adding a few tasks to it over an array of strings, and for each string, calling a function to insert this string as our `text` field in our `task` document. @@ -62,13 +64,15 @@ Now comes the fun part, you will render the tasks saved in our database. With Sv On your file `App.svelte`, import the `TasksCollection` file and, instead of returning a static array, return the tasks saved in the database. Let's use an extension of the Svelte's [$ reactive statements](https://svelte.dev/docs#3_$_marks_a_statement_as_reactive) feature, to maintain your tasks, called [$m](https://github.com/zodern/melte#tracker-statements): +Because it is an asynchronous function, we need to use the `#await` keyword to wait for the data to be fetched from the database. More information about how Svelte handles asynchronous values can be found [here](https://svelte.dev/docs#template-syntax-await). + `imports/ui/App.svelte` -```html +```sveltehtml @@ -77,11 +81,17 @@ On your file `App.svelte`, import the `TasksCollection` file and, instead of ret

    Todo List

    -
      - {#each tasks as task (task._id)} - - {/each} -
    + {#await getTasks} +

    Loading...

    + {:then tasks} +
      + {#each tasks as task (task._id)} + + {/each} +
    + {:catch error} +

    {error.message}

    + {/await} ``` diff --git a/tutorial/simple-todos/03-forms-and-events.md b/tutorial/simple-todos/03-forms-and-events.md index 2e9bb9f..76fc561 100644 --- a/tutorial/simple-todos/03-forms-and-events.md +++ b/tutorial/simple-todos/03-forms-and-events.md @@ -27,7 +27,7 @@ Then we can simply add this new form to our `App.svelte` component by first impo `imports/ui/App.svelte` -```html +```sveltehtml .. ``` diff --git a/tutorial/simple-todos/04-update-and-remove.md b/tutorial/simple-todos/04-update-and-remove.md index 3a26959..3f1918b 100644 --- a/tutorial/simple-todos/04-update-and-remove.md +++ b/tutorial/simple-todos/04-update-and-remove.md @@ -10,7 +10,7 @@ First, you need to add a `checkbox` element to your `Task` component: `imports/ui/Task.svelte` -```html +```sveltehtml
  • { - // Set the isChecked property to the opposite of its current value - TasksCollection.update(task._id, { - $set: { isChecked: !task.isChecked } - }); + const toggleChecked = async () => { + // Set the checked property to the opposite of its current value + await TasksCollection.updateAsync(task._id, { + $set: { isChecked: !task.isChecked } + }); }; .. @@ -78,8 +78,8 @@ Now add the removal logic inside the ` .. diff --git a/tutorial/simple-todos/05-styles.md b/tutorial/simple-todos/05-styles.md index f8013ba..2951a5e 100644 --- a/tutorial/simple-todos/05-styles.md +++ b/tutorial/simple-todos/05-styles.md @@ -156,7 +156,7 @@ Now you need to add some elements around your components. Also, we need to apply `imports/ui/App.svelte` -```html +```sveltehtml ..
    @@ -169,12 +169,17 @@ Now you need to add some elements around your components. Also, we need to apply
    - -
      - {#each tasks as task (task._id)} - - {/each} -
    + {#await getTasks} +

    Loading...

    + {:then tasks} +
      + {#each tasks as task (task._id)} + + {/each} +
    + {:catch error} +

    {error.message}

    + {/await}
    diff --git a/tutorial/simple-todos/06-filter-tasks.md b/tutorial/simple-todos/06-filter-tasks.md index a29d725..57364e8 100644 --- a/tutorial/simple-todos/06-filter-tasks.md +++ b/tutorial/simple-todos/06-filter-tasks.md @@ -12,7 +12,7 @@ With Svelte this will be a pretty simple task as we don't have to do much to kee `imports/ui/App.svelte` -```html +```sveltehtml .. @@ -88,7 +88,7 @@ Install it in your Google Chrome browser using this [link](https://chrome.google ## 6.5: Pending tasks -Update the App component in order to show the number of pending tasks in the app bar. +Update the App component in order to show the number of pending tasks in the app bar. Remember that your calls to the database are asynchronous, so you need to use the `#await` keyword to get the data. You should avoid adding zero to your app bar when there are not pending tasks. @@ -97,19 +97,17 @@ You should avoid adding zero to your app bar when there are not pending tasks. @@ -117,7 +115,11 @@ You should avoid adding zero to your app bar when there are not pending tasks.
    -

    📝️ To Do List {pendingTasksTitle}

    + {#await getCount} +

    📝️ To Do List (...)

    + {:then count} +

    📝️ To Do List {pendingTitle(count)}

    + {/await}
    diff --git a/tutorial/simple-todos/07-adding-user-accounts.md b/tutorial/simple-todos/07-adding-user-accounts.md index 66be49b..d3b8c27 100644 --- a/tutorial/simple-todos/07-adding-user-accounts.md +++ b/tutorial/simple-todos/07-adding-user-accounts.md @@ -36,7 +36,7 @@ import { TasksCollection } from '/imports/api/TasksCollection'; const SEED_USERNAME = 'meteorite'; const SEED_PASSWORD = 'password'; -Meteor.startup(() => { +Meteor.startup(async () => { if (!Accounts.findUserByUsername(SEED_USERNAME)) { Accounts.createUser({ username: SEED_USERNAME, @@ -112,7 +112,7 @@ You can get your authenticated user or null from `Meteor.user()`. Then you can v `imports/ui/App.svelte` -```html +```sveltehtml @@ -283,17 +289,23 @@ Now you can filter the tasks in the UI by the authenticated user. Use the user ` ..
    .. + {#await getTasks} +

    Loading...

    + {:then tasks}
      {#each tasks as task (task._id)} - + {/each}
    + {:catch error} +

    {error.message}

    + {/await} ..
    ``` -Also update the `insert` call to include the field `userId` in the `TaskForm`. You should pass the user from the `App` component to the `TaskForm`. +Also update the `insertAsync` call to include the field `userId` in the `TaskForm`. You should pass the user from the `App` component to the `TaskForm`. `imports/ui/TaskForm.svelte` ```html @@ -301,9 +313,9 @@ Also update the `insert` call to include the field `userId` in the `TaskForm`. Y .. export let user = null; .. - const handleSubmit = () => { + const handleSubmit = async () => { // Insert a task into the collection - TasksCollection.insert({ + await TasksCollection.insertAsync({ text: newTask, createdAt: new Date(), // current time userId: user._id, diff --git a/tutorial/simple-todos/08-methods.md b/tutorial/simple-todos/08-methods.md index 199f631..bb53b46 100644 --- a/tutorial/simple-todos/08-methods.md +++ b/tutorial/simple-todos/08-methods.md @@ -58,45 +58,46 @@ import { check } from 'meteor/check'; import { TasksCollection } from './TasksCollection'; Meteor.methods({ - 'tasks.insert'(text) { + async 'tasks.insert'(text) { check(text, String); - + if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - - TasksCollection.insert({ + + await TasksCollection.insertAsync({ text, createdAt: new Date(), userId: this.userId, - }) + }); }, - - 'tasks.remove'(taskId) { + + async 'tasks.remove'(taskId) { check(taskId, String); - + if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - - TasksCollection.remove(taskId); + + await TasksCollection.removeAsync(taskId); }, - - 'tasks.setIsChecked'(taskId, isChecked) { + + async 'tasks.setIsChecked'(taskId, isChecked) { check(taskId, String); check(isChecked, Boolean); - + if (!this.userId) { throw new Meteor.Error('Not authorized.'); } - - TasksCollection.update(taskId, { + + await TasksCollection.updateAsync(taskId, { $set: { - isChecked - } + isChecked, + }, }); - } + }, }); + ``` As you can see in the code we are also using the `check` package to make sure we are receiving the expected types of input, this is important to make sure you know exactly what you are inserting or updating in your database. diff --git a/tutorial/simple-todos/09-publications.md b/tutorial/simple-todos/09-publications.md index b013f81..0342334 100644 --- a/tutorial/simple-todos/09-publications.md +++ b/tutorial/simple-todos/09-publications.md @@ -56,7 +56,7 @@ As we want to receive changes from this publication we are going to `subscribe` `imports/ui/App.svelte` -```html +```sveltehtml .. @@ -139,42 +140,42 @@ Only the owner of a task should be able to change certain things. You should cha ```js .. - 'tasks.remove'(taskId) { - check(taskId, String); - - if (!this.userId) { - throw new Meteor.Error('Not authorized.'); - } - - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); - - if (!task) { - throw new Meteor.Error('Access denied.'); - } - - TasksCollection.remove(taskId); - }, - - 'tasks.setIsChecked'(taskId, isChecked) { - check(taskId, String); - check(isChecked, Boolean); - - if (!this.userId) { - throw new Meteor.Error('Not authorized.'); - } - - const task = TasksCollection.findOne({ _id: taskId, userId: this.userId }); - - if (!task) { - throw new Meteor.Error('Access denied.'); - } - - TasksCollection.update(taskId, { - $set: { - isChecked, - }, - }); - }, + async 'tasks.remove'(taskId) { + check(taskId, String); + + if (!this.userId) { + throw new Meteor.Error('Not authorized.'); + } + + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); + + if (!task) { + throw new Meteor.Error('Access denied.'); + } + + await TasksCollection.remove(taskId); + }, + + async 'tasks.setIsChecked'(taskId, isChecked) { + check(taskId, String); + check(isChecked, Boolean); + + if (!this.userId) { + throw new Meteor.Error('Not authorized.'); + } + + const task = await TasksCollection.findOneAsync({ _id: taskId, userId: this.userId }); + + if (!task) { + throw new Meteor.Error('Access denied.'); + } + + await TasksCollection.updateAsync(taskId, { + $set: { + isChecked, + }, + }); + }, .. ``` diff --git a/tutorial/simple-todos/11-testing.md b/tutorial/simple-todos/11-testing.md index bd2657d..7ac7277 100644 --- a/tutorial/simple-todos/11-testing.md +++ b/tutorial/simple-todos/11-testing.md @@ -82,9 +82,9 @@ if (Meteor.isServer) { const userId = Random.id(); let taskId; - beforeEach(() => { - TasksCollection.remove({}); - taskId = TasksCollection.insert({ + beforeEach(async () => { + await TasksCollection.removeAsync({}); + taskId = await TasksCollection.insertAsync({ text: 'Test Task', createdAt: new Date(), userId, @@ -130,11 +130,12 @@ if (Meteor.isServer) { }); }); - it('can delete owned task', () => { + it('can delete owned task', async () => { mockMethodCall('tasks.remove', taskId, { context: { userId } }); - assert.equal(TasksCollection.find().count(), 0); + assert.equal(await TasksCollection.find().countAsync(), 0); }); + }); }); } @@ -162,53 +163,53 @@ if (Meteor.isServer) { const userId = Random.id(); let taskId; - beforeEach(() => { - TasksCollection.remove({}); - taskId = TasksCollection.insert({ + beforeEach(async () => { + await TasksCollection.removeAsync({}); + taskId = await TasksCollection.insertAsync({ text: 'Test Task', createdAt: new Date(), userId, }); }); - it('can delete owned task', () => { + it('can delete owned task', async () => { mockMethodCall('tasks.remove', taskId, { context: { userId } }); - assert.equal(TasksCollection.find().count(), 0); + assert.equal(await TasksCollection.find().countAsync(), 0); }); - it(`can't delete task without an user authenticated`, () => { + it("can't delete task without an user authenticated", async () => { const fn = () => mockMethodCall('tasks.remove', taskId); assert.throw(fn, /Not authorized/); - assert.equal(TasksCollection.find().count(), 1); + assert.equal(await TasksCollection.find().countAsync(), 1); }); - it(`can't delete task from another owner`, () => { + it("can't delete task from another owner", async () => { const fn = () => mockMethodCall('tasks.remove', taskId, { context: { userId: 'somebody-else-id' }, }); assert.throw(fn, /Access denied/); - assert.equal(TasksCollection.find().count(), 1); + assert.equal(await TasksCollection.find().countAsync(), 1); }); - it('can change the status of a task', () => { - const originalTask = TasksCollection.findOne(taskId); + it('can change the status of a task', async () => { + const originalTask = await TasksCollection.findOneAsync(taskId); mockMethodCall('tasks.setIsChecked', taskId, !originalTask.isChecked, { context: { userId }, }); - const updatedTask = TasksCollection.findOne(taskId); + const updatedTask = await TasksCollection.findOneAsync(taskId); assert.notEqual(updatedTask.isChecked, originalTask.isChecked); }); - it('can insert new tasks', () => { + it('can insert new tasks', async () => { const text = 'New Task'; mockMethodCall('tasks.insert', text, { context: { userId }, }); - const tasks = TasksCollection.find({}).fetch(); + const tasks = await TasksCollection.find({}).fetchAsync(); assert.equal(tasks.length, 2); assert.isTrue(tasks.some(task => task.text === text)); }); @@ -216,6 +217,7 @@ if (Meteor.isServer) { }); } + ``` If you run the test command again or left it running in watch mode before, you should see the following output: