Svelte store not triggered when value chages, only when $: is prefixed - store

As I understand, when using Svelte store with $ prefixed it's automatically subscribed to value changes.
Having the following code, whenever users.name store value is changed it should trigger one of the two statements.
<script>
if (!$userS.name) {
list = Promise.reject({message:'You are not allowed to view this section!'});
} else {
list = getList('api/carousel/' + escape(term));
}
</script>
But the only way the previous code is working is when the if statement it's prefixed by "$:".
$: if (!$userS.name) { ...
So why is need the extra reactive dollar sign if it's already subscribed to store value changes?

Your component init script, that is the code inside the<script> tag, is not reactive. It runs once when your component is created and that's all. Think class constructor.
Only the code in reactive blocks $: is kept in sync and reruns when (reactive) variables they contain change.
The $ prefix gives you the value inside the store. In your example, the user variable is the store itself. console.log it, you'll see it is an object with a subscribe method etc. The prefixed variable gives you the value inside the store. Behind the scene, Svelte makes a subscription to the store (i.e. calls its subscribe method) when your component is created, and unsubscribes when it is destroyed.
Meanwhile, if the value changes, the $ prefixed variable will be reactive. But it will only have an effect if it sits in a reactive context. That is, either a reactive expression/statement $:, or in the markup. This is true for any reactive source (props, top level variables...).

Related

Node - look up the value of an arbitrary variable

Take this code for an example:
(() => {
const data = []
const ws = new WebSocket('ws:/localhost:5555');
ws.onmessage = (frame) => data.push(frame.data);
})();
Is it possible to look up the value of data without stopping the application, or breakpointing onmessage and waiting for it to occur? Is it possible to just look up the value of any variable that I know to be stored persistently somewhere?
Variables inside a function are private to within that function scope. Only code inside that function scope can examine them.
If you're in the debugger, you will need to be at a breakpoint inside that function scope in order to see that variable.
Sometimes it's appropriate to move the declaration of a variable to a higher scope so that after it is modified inside some local scope, it's value will persist and can be accessed from a higher scope. I don't know what real problem you're trying to solve here to know whether that makes sense for your situation or not.
More likely, since variables like your data variable get modified at some unknown time, the only way some outside code can know when to look at an updated value is by participating in some sort of event system or callback system that notifies outside that it now has a new value. In that case, it's common to just pass the new value to the callback or along with the event. Then the outside code gets the value that way, rather than having to declare it in some parent scope.

LitElement and .bind(this)

I'm finding a little confusing sometimes you need to bind the context to a function call and sometimes not. When exactly can you avoid it and when you not?
What's the difference between those lines?
<a #click="${this.handler.bind(this)}">link</a>
<a #click="${this.handler()}">link</a>
<a #click="${this.handler}">link</a>
<a #click="${()=>this.handler()}">link</a>
Also sometimes in the constructor() you need
this.handler = this.handler.bind(this)
to make the function call works, sometimes you not. What's the differences between all those cases?
In the first 4 lines I am guessing you usually wrap them in between ${ and }.
With this mention these 3 lines:
<a #click="${this.handler.bind(this)}">link</a>
<a #click="${this.handler}">link</a>
<a #click="${()=>this.handler()}">link</a>
would be pretty similar in the effect. When you attach an event handler you need to pass a reference to a function/method to call, while the second line:
<a #click="${this.handler()}">link</a>
will most likely just be wrong. That's because you will be calling this.handler() as soon as the rendering is done. The only way it might make some sense it would be if the handler method returns a function.
Going back to the first 3 lines: they will indeed have very similar effect, as in all of them you are passing references to a local method render, but:
the first one doesn't need binding as the method will anyway be
called in this context (but I guess it doesn't hurt either)
the third one adds the definition of an anonymous function as an
event handler, which when called it will invoke this.handler
So the second one is basically the simplest and easiest to read.
When it comes to the need to call bind in some of the cases: that's needed when your method is called from another context. Let's say you pass it as a callback parameter to a method running in another class. When you method will be called there, it will have by default the context of that other object. So you will need to use .bind(this) to make sure that when the method is called in your element's context.
Your method does work, but it's running from another this. So maybe that's why some of the times you don't notice the need to .bind(this). If the method just shows a message, calls some other external service, or anything else that is not part of your object's definition (that doesn't use this.something), it will work without using bind.
UPDATE: in fact I think an event handler will always run in the context of the element that originated that event. I am guessing that lit just does that .bind(this) when we use that #click= syntax, as it would make a lot of sense.
Note that binding directly in templates is generally not a good idea. It can result in performance issues and components re-rendering when they shouldn't.
https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/no-template-bind.md
As to why you sometimes need to bind consider this:
#customElement('main-page')
export class MainPage extends LitElement {
#property()
public name = "bob";
render() {
return html`<button #click=${this.clicked}>Click Me!</button>`;
}
clicked() {
console.log("clicked " + this.name);
console.log("this in clicked: " + this)
setTimeout(this.sayHi, 1000);
}
sayHi() {
console.log("this in sayHi: " + this)
alert(`Hello, ${this.name}!`);
}
}
If we click on the button, we get the name logged properly:
But the name isn't shown in the alert:
If we look at this in both functions we get different results:
One is an HTMLElement and the other one is a Window. What this refers to is different once we pass sayHi to setTimeout.
Bind will fix this by making sure that this refers to the right object.
While we could do setTimeout(this.sayHi.bind(this), 1000); and it would fix our issue but it's not very clean and it's error prone. We could bind it in the constructor, but this also isn't much better.
The cleanest way to do it is to directly bind this by using an arrow function instead:
sayHi = () => {
[...]
This notation binds this to the object itself. We then do not need to bind it explicitly ourselves.
Once we do that, both this refer to the right object:

Set temporary variable and reuse it further down in pug template

I am trying to pass along some values from my nodejs/express backend into the template (using res.render({...})), store it in some variables, then pass it further up until the front end (The usecase is that I need to do some mild calculation on the passed values and stored them in some intermediate variables)
I know I can do this in the pug file
block append script
script.
const foo = parseInt(#{stat.get('fooStat')}, 10);
But then later it seems that I can not refer to this later in my pug template, say here
span #{foo}
The value is empty, I guess because it is undefined... What's the usual way to accomplish that.
Adding the period after the script tag signals to pug that its contents should be treated as plain text. This is handy when you want to write javascript for client-side consumption, but any variables declared are inaccessible to pug.
script.
const foo = 10;
span #{foo} // foo is undefined here
If you want to define a variable that pug can use later in the template, do so using unbuffered code.
- const foo = 10
span #{foo} // renders <span>10</span>

Why in Mojito, renaming controller.server.js to controller.server-foo.js will have no effect?

In Mojito on top of Node.js, I followed the example on http://developer.yahoo.com/cocktails/mojito/docs/quickstart/
What I did was renaming controller.server.js to controller.server-foo.js, and created a new file controller.server.js to show "Hello World".
But when mojito is started, the old file controller.server-foo.js is being used and so the "Hello World" is not printed. How come Mojito will use the old file?
(I also tried renaming controller.server-foo.js to foo-controller.server.js and now the "Hello World" is printed, but why is controller.server-foo.js used?)
I found out that historically, the "affinity" of the controller can be two parts. The first part is common, server, or client, and the second part is optional, and it might be tests, or other words, so use other names such as controller-not-used-server.js to disable it.
#Charles, there are 3 registration processes in mojito (yes, it is confusing at first):
Affinity (server, client or common).
YUI.add when creating yui modules (controllers, models, binders, etc)
and the less common which is the registration by name (which includes soemthing that we call selectors)
In your case, by having two controllers, one of them with a custom selector named "foo", you are effectible putting in use the 3 registration at once. Here is what happen internally:
A controller is always detonated as "controller" filename from the mojit folder, which is part of the registration by name, and since you have "foo" selector for one of the controller, your mojit will have to modes, "default" and "foo". Which one of them will be use? depends on the application.json, where you can have some conditions to set the value of "selector", which by default is empty. If you set the value of selector to "foo" when, for example, device is an iphone, then that controller will be used when that condition matches.
Then the YUI.add plays an important role, it is the way we can identify which controller should be used, and its only requirement is that NO OTHER MODULE in the app can have the same YUI Module name, which means that your controllers can't be named the same when registering them thru YUI.add. And I'm sure this is what is happening in your case. If they both have the same name under YUI.add() one will always override the other, and you should probably see that in the logs as a warning, if not, feel free to open an issue thru github.
To summarize:
The names used when registering YUI modules have to be unique, in your case, you can use: YUI.add('MyMojit', function(){}) and YUI.add('MyMojitFoo', function(){}), for each controller.
Use the selector (e.g.: controller.server-mobile.js) to select which YUI module should be used for a particular request by setting selector to the proper value in application.json.

Enumerate events/eventListeners for a WinJS object

I'm using pure WinJS for a project (No jQuery) and have run into a requirement that has me stumped.
Let's say I have a DOM element called 'bob' (although this might not necessarily be a DOM element). To attach an event listener, I would do this:
bob.addEventListener('click', function ()
{
// Some code goes here
});
There is nothing stopping me from adding lots of event listeners to 'bob', even for the same event names (which is fine as they are just queued) - herein lies the rub!
I need to be able to enumerate the events/listeners that are attached to a given object so I can selectively replace or tweak some of them at runtime.
Any thoughts on how to acheive this?
It's not possible to enumerate events added using addEventListener. The way you're adding the event is not recommended (at least by me :). You're using addEventListener but then using an anonymous method. If you do that then you'll never be able to remove that event because you don't have a handle to it. I would recommend creating your function and then assigning the named function (myelement.addEventListener("event", myfunction)). Each time you add an event to your element, just add it to a collection (an array hanging off the element itself) and then you'll have your list of events.
It turns out that you can, in some circumstances, enumerate attached event listeners.
If you are using the 'Events' Mixin on an object, then once you have called one of the mixed-in methods (addEventListener, removeEventListener or dispatchEvent), your target object will gain a property called _listeners (assuming it doesn't already exist).
For a practical example, here's a function that counts the number of attached event listeners for an object that uses this mixin:
/*
* Counts the number of attached listeners
*/
countListeners: function()
{
var count = 0;
if (this._listeners)
{
var key;
for (key in this._listeners)
{
if (this._listeners.hasOwnProperty(key))
{
count++;
}
}
}
return count;
}
Hope this helps someone!
G

Resources