This question already has answers here:
Checking auth token valid before route enter in Vue router
(5 answers)
Closed 2 years ago.
I want to test if the user has login or not, if not he will return to login page.
I want the script that check if the user has login to be executed before html (or template) load.
I have tried
beforeCreate()
and other things, but html still load before the script run.
this is my code
if(sessionStorage.getItem("email") == undefined) location.href = "/";
edit
I made this vue project using CLI so I dont have the normal index.html with head and body where i can simply add script anywhere outside vue.
It isn't considered "best practice" to implement security code using JavaScript. If a user turns off JavaScript in their browser, they have effectively bypassed your security.
Instead, use server-side code to detect if the current user is logged in, and if not, send an HTML redirect to the login page instead of the normal HTML content.
Pseudo code (as you haven't specified any server-side language):
if(userLogin <> true)
Return HtmlRedirect("YourLoginPage")
...
Return CuurrentPage
This method prevents any HTML being sent to the user if they are not authorised to see it.
try checking if your condition matches before initiating vue instance and initiate it after satisfying the condition like this:
if(sessionStorage.getItem("email") == undefined) {
location.href = "/";
} else {
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
}
I agree with #Dragonlaird said mentioning that it is not a best practice to handle it from the client-side. However, I think you have to try beforeMount or beforeUpdate instead of beforeCreate since you need to do the stuff before HTML (or template) load. According to the Vue.js documentation,
beforeMount:
It is called right before the mounting begins: the render function is about to be called for the first time.
But this hook(beforeMount) is not called during server-side rendering.
beforeUpdate:
It is called when data changes before the DOM is patched. This is a good place to access the existing DOM before an update, e.g. to remove manually added event listeners.
This hook is also not called during server-side rendering, because only the initial render is performed server-side.
For further information please refer Vue.js documentation.
https://v2.vuejs.org/v2/api/#Options-Lifecycle-Hooks
Related
I'm used to using Express with a templating engine, like Handlebars. I want to start working with Svelte and SvelteKit, but I'm unsure how to start working with both. I am stuck on passing data to the frontend from the server. In Express, I'd normally connect to the database, and then pass the data to res.render, where the templating engine would then take over. So far, I think I have to run a handle function to pass the data, and then I can access it from my page. But it seems that the handle function runs for every request, and if all my pages require different data, does that mean I have to use a giant switch statement or something for every page?
Can anybody tell me if that's the right way to pass data over, or if there's a better way. Sorry, I'm fairly new to metaf rameworks and Svelte.
There are two ways to achieve what you want to do.
Let for both cases assume you have an about page and want to show dynamic data on this page like some team members. You would have a file called about.svelte (this makes the /about route) with in it something like:
<script>
export let team = [];
</script>
{#each team as member}
...
{/each}
Now how to get the team data to the page itself ?
the load function
The first option is the load function, this is a function that runs before the page is loaded and can be used to fetch data for this page. You would put the following block in about.svelte, usually before the other script block:
<script context="module">
export async function load({ fetch }) {
const team = await fetch('/api/team').then(res => res.json());
return {
props: {
team
}
}
}
</script>
Important to note with this one is that you need some sort of api (/api/team in this case) that can give you the data.
a page endpoint
The second option is to make a so called page endpoint this acts as a kind of api and lives next to the page itself. In the same folder as about.svelte add a file about.js:
export async function get() {
const team = []; // add team data here somehow
return {
status: 200,
body: {
team
}
}
what's the difference ?
When to use which approach is mostly up to you, but you have to remember the following two things:
The load function will likely need another api somewhere (this does not have to be SvelteKit)
The load function is, on the first page, executed on the server and afterwards will always run on the client. The endpoint on the other hand always runs serverside.
Im not really sure if Im understanding correctly the way observables work and how to get references from mounted tags. I have a component. Within this component we have a component and a component. The purpose is to avoid coupling between components. Because of that, I would like that my search component triggers an event when a search is done(a button is clicked). This event should be caught by the component which will filter the collection data based on the search.
The index.html file load the tag by using:
index.html
riot.mount(".content", "page", null);
The page is defined as follow:
page.js
<page>
<!-- Search tag controls -->
<search id="searchTag"></search>
<!-- Collection data to display -->
<collection id="collectionTag"></collection>
</page>
The component script is briefly defined like:
search.js
var self = this;
riot.observable(self);
<!-- This function is called when the user click on the button. -->
self.filtering = function()
{
<!-- We get data from inputs -->
var info = Getting data from inputs;
<!-- Trigger the event hoping that someone will observe it -->
self.trigger("filterEvent", info);
}
How can I make the component observe for that event?
To me it seems that I should be able to get references from search tag and collection tag in the page.js. By doing so I could connect the events like follow:
searchComponent = riot.mount('search');
collectionComponent = riot.mount('collection');
searchComponent.on('filterEvent', function()
{
<!-- Trigger function to filter collection data -->
collectionComponent.trigger('filterData');
});
Right now I cannot make it work like that.
At the point of execution, searchComponent and collectionComponent are not defined.
I tried also getting references of these component by using this.searchTag and this.collectionTag instead of mounting them but at the time the code is executed, the components have not been mounted and so I dont get a reference to them.
Any ideas to make it work?
Inspired by the answer given by #gius, this is now my preferred method for sending events in RiotJS from one tag to another.. and it is great to work with!
The difference from #gius approach being that, if you use a lot of nested tags, passing a shared Observable to each tag falls short, because you would need to pass it again and again to each child tag (or call up from the child tags with messy this.parent calls).
Defining a simple Mixin, like this (below), that simply defines an Observable, means that you can now share that in any tag you want.
var SharedMixin = {
observable: riot.observable()
};
Add this line to your tags..
this.mixin(SharedMixin);
And now, any tag that contains the above line can fire events like..
this.observable.trigger('event_of_mine');
..or receive events like this..
this.observable.on('event_of_mine',doSomeStuff());
See my working jsfiddle here http://jsfiddle.net/3b32yqb1/5/ .
Try to pass a shared observable to both tags.
var sharedObservable = riot.observable();
riot.mount('search', {observable: sharedObservable}); // the second argument will be used as opts
riot.mount('collection', {observable: sharedObservable});
And then in the tags, just use it:
this.opts.observable.trigger('myEvent');
this.opts.observable.on('myEvent', function() { ... });
EDIT:
Or even better, since your search and collection tags are child tags of another riot tag (page) (and thus you also don't need to mount them manually), you can use the parent as the shared observable. So just trigger or handle events in your child tags like this:
this.parent.trigger('myEvent');
this.parent.on('myEvent', function() { ... });
Firstly I do not understand your file structure !
In your place I would change filenames :
page.js --> page.tag
search.js --> search.tag
And i dont see your search tag in search.js code.
So I dont see your Collection tag file ...
Are you sure that this one use this code ?
riot.observable({self|this});
Because it's him who will receive an Event.
For me when I use Riot.js(2.2.2) in my browser, if I use
searchComponent = riot.mount('search');
searchComponent will be undefined
But with this code you can save your monted tag reference :
var searchComponent ={};
riot.compile(function() {
searchComponent = riot.mount('search')[0];
});
Another option is to use global observables, which is probably not always best practice. We use Riot's built in conditionals to mount tags when certain conditions are met rather than directly mounting them via JS. This means tags are independent of each other.
For example, a single observable could be used to manage all communication. This isn't a useful example on its own, it's just to demonstrate a technique.
For example, in a plain JS file such as main.js:
var myApp = riot.observable();
One tag file may trigger an update.
var self = this;
message = self.message;
myApp.trigger('NewMessage', message);
Any number of other tag files can listen for an update:
myApp.on('NewMessage', function(message) {
// Do something with the new message "message"
console.log('Message received: ' + message);
});
Maybe overkill but simple. let riot self observable
riot.observable(riot);
So you can use
riot.on('someEvent', () => {
// doing something
});
in a tag, and
riot.trigger('someEvent');
in another.
It's not good to use global variable, but use an already exists one maybe acceptable.
I've been going through this tutorial on ReactJS.NET, and hit a snag. It mentions that:
We will use simple polling here but you could easily use SignalR or other technologies.
While this works when I do client-side rendering, it throws the following error when rendering server-side. Currently, I don't actually need jQuery or SignalR to render the initial state as I'm only using them to subscribe to updates once the app is running. I guess my question is, what is the correct way to structure my React application so that I can render it server-side or client-side at will.
Error while loading "~/Scripts/jquery-1.10.2.js": ReferenceError: window is not defined
Got it working (live demo), I just needed to move the call to React.render outside of the jsx file and pass in what I needed (see snippet below). Another option would be to try and mock the expected objects with jsdom.
<!-- Render the React Component Server-Side -->
#Html.React("CommentBox", new
{
data = Model,
conn = false
})
<!-- Optionally Render the React Component Client-Side -->
#section scripts {
<script src="~/Scripts/react/react-0.12.2.js"></script>
#Scripts.Render("~/bundles/comments")
<script>
React.render(React.createElement(CommentBox, {
data: #Html.Raw(Json.Encode(Model)),
conn: $.hubConnection()
}), document.getElementById("react1"));
</script>
}
Using jQuery while rendering server side using reactjs.net:
The answer is a partial Yes if you put the jQuery in the ComponentDidMount function of React with your setup above.
Like this:
componentDidMount: function(){
if (this.props.userID == 0){
$("#postButton").hide();
}
}
It also worked in some other places but not everywhere. Other places in the React script, I got "ReferenceError: $ is not defined".
Here's some additional comments by the reactjs.net author himself. Basically, jQuery is not designed to work server side so prob best not to rely on it.
https://groups.google.com/forum/#!topic/reactjs/3y8gfgqJNq4
As an alternative, for instance, if you want to control the visibility of an element without using jQuery, you can create a style and then assign the style based on If logic. Then add the style as an inline attribute to the element as shown below. This should work fine in React.
var styleComment = {display: 'block'};
if (this.props.commentCount == 0){
styleComment = {display: 'none'}
}
<div style={styleComment}>Count is greater than 0</div>
In my app I use accounts-github. Works perfect, but I have one problem.
In one of my templates I do
Template.bar.rendered = function () {
if (Meteor.user()) {
// setup stuff
}
}
The problem is that if the user initially is not logged in this code is not executed (thats ok). But when the user authenticates this code is not executed again. So the question is how can I listen for this change inside a template (doesn't have to be in inside the rendered function!)?
You could use Deps.autorun. (http://docs.meteor.com/#deps_autorun)
Usually Deps.autorun would run for your whole Meteor app. If you want to make it so that it only runs per template you would need to create and stop it in the rendered and destroyed template callbacks
e.g
var loginRun;
Template.bar.rendered = function() {
loginRun = Deps.autorun(function() {
if(Meteor.user()) {
//Stuff to run when logged in
}
});
}
Template.bar.destroyed = function() {
loginRun.stop();
}
If you don't need it to run per template (need it to run just once for you app on any template, then you can use the Deps.autorun on its own, anywhere in your client side code.
Meteor.user() is reactive, it would ensure that the Deps.autorun callback runs again when it changes, so you could theoretically use it to do things when the user logs in or out.
Other alternatives is there is a package on atmosphere that provides login and logout hooks, though they basically would use the Deps.autorun like above to work anyway. See https://github.com/BenjaminRH/meteor-event-hooks
My solution for similar problem was to
Attach an event to template where the login happens
Re-render template if login is succesful so the Template.bar.rendered is called
E.g.
Template.bar.events({
'click .loginButton' : function() {
if( Meteor.call.Login( username, pw ) )
{
$('#bar').html( Meteor.render( Template.bar ));
//jQuery is optional
}
});
I've been poking around in the Accounts packages, using a modified version of the ever-fabulous EventedMind Customizing Login screencast.
I modified it to use facebook instead of github, and I noticed something when trying to update user.profile information. Specifically, I'm looking for the right way/place to handle changes to user.profile.
Let's say, for example, that I authenticate as a FB user for the first time. When I do this, the CreateUser event will fire.
Using Accounts.onCreateUser(...), I can populate additional information from the FB graph into the profile, like so:
Accounts.onCreateUser(function(options,user){
var accessToken = user.services.facebook.accessToken,
result;
result = Meteor.http.get("https://graph.facebook.com/"+user.services.facebook.username, {
params: {
access_token:accessToken,
fields: ['picture', 'name','first_name','last_name','username','link','location','bio','relationship_status','email','timezone','locale']
}
});
if (result.error){
throw result.error;
}
user.profile = result.data; //lazily adding everything
return user;
});
This works just fine when the user is created. It's nice and clean.
But now let's say that some of the information changes. For example, let's say that the profile picture changes. If I log out and then back in to the meteor application, Accounts.onCreateUser(...) doesn't fire, because the user already exists. It's not being created again, it's being modified.
I need to update the user.profile on subsequent logins, or at least check for changes and then modify as needed. I'd ideally like to do this in similar fashion to .onCreateUser. Maybe with a .onModifyUser or something...
I can figure a couple of ways to do this using some checking and/or client-side code, but I'm wondering if there is an already-existing server hook that would be cleaner.
Any recommendations on the cleanest way to handle this situation?
Thanks in advance.
If you're manually calling the login functions you can pass a callback as the last parameter which will get called on the client after the login completes. See: http://docs.meteor.com/#meteor_loginwithpassword.
Meteor.loginWithFacebook({}, function (err) { /* make a Meteor method call here */ });
There are no documented server side callbacks at the moment.