I have written shell.js
define(['plugins/router', 'durandal/app'], function (router, app) {
return {
router: router,
activate: function () {
router.map([
{ route: 'login', title: 'login', moduleId: 'viewmodels/login', nav: true }
]).buildNavigationModel();
return router.activate();
}
};
});
and shell.html
<div>
<nav role="navigation">
<div>
<ul data-bind="foreach: router.navigationModel">
<li data-bind="css: { active: isActive }">
<a data-bind="attr: { href: hash }, text: title"></a>
</li>
</ul>
</div>
</nav>
<div class="page-host" data-bind="router: { transition:'entrance' }"></div>
My login.js is
define(['require', 'knockout', 'durandal/system', 'durandal/app', 'plugins/router', 'jquery'],
function (require, ko, system, app, router, $) {
var loginVM = function () {
var self = this;
self.username = ko.observable();
self.password = ko.observable();
};
return loginVM;
});
and login.html is
<div id="openModal">
<div>
<h4>Please login to proceed</h4>
<div class="row">
<div>
<label for="Username">Username:</label>
<input type="text" id="Username" data-bind="value: userName, hasFocus: setFocus" />
</div>
</div>
<div>
<div>
<label for="Password">Password:</label>
<input type="password" id="Password" data-bind="value: password">
</div>
</div>
<div>
<button id="login" onclick="Users.login()" type="submit" data-bind="click: login, disable: session.isBusy()">Log in</button>
</div>
<p id="warning" class="warning">Invalid username or password !!!</p>
</div>
I am trying to open login page from shell. Can anyone help me with this if i am doing anything wrong as login page is not loading after shell.
I figured out the problem. Path for moduleId: 'viewmodels/login' was wrong so I made it as moduleId: 'app/viewmodels/login' and now login page is loading.
Related
I'm relatively new to Vue and super stuck with this error message when I try to make this reset email modal work in my Vue project:
Property or method "sendResetMail" is not defined on the instance but
referenced during render. Make sure that this property is reactive,
either in the data option, or for class-based components, by
initializing the property.
I have no idea what I need to do to make this work. I followed the Vue documentation and declared resetEmail in the data option.
ForgotPassword.vue:
<template>
<section>
<a #click="isComponentModalActive = true">
Forgot Password?
</a>
<b-modal :active.sync="isComponentModalActive" has-modal-card>
<modal-form v-bind="resetEmail"></modal-form>
</b-modal>
</section>
</template>
<script>
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'
const ModalForm = {
props: ['resetEmail'],
template: `
<form #submit.prevent="sendResetMail">
<div class="modal-card" style="width: auto">
<header class="modal-card-head">
<p class="modal-card-title">Forgot password?</p>
</header>
<section class="modal-card-body">
<b-field label="Email">
<b-input
type="email"
:value="resetEmail"
placeholder="Your email"
required>
</b-input>
</b-field>
</section>
<footer class="modal-card-foot">
<button class="button" type="button" #click="$parent.close()">Close</button>
<button class="button is-primary">Reset</button>
</footer>
</div>
</form>
`
}
export default {
components: {
ModalForm
},
data () {
return {
isComponentModalActive: false,
resetEmail: '',
feedback: null
}
},
methods: {
sendResetMail () {
var auth = firebase.auth()
var emailAddress = this.resetEmail
auth.sendPasswordResetEmail(emailAddress).then(function () {
// Email sent.
console.log('email send')
}).catch(function (error) {
// An error happened.
this.feedback = error.message
console.log(error.message)
})
}
}
}
</script>
This is the file where I use the ForgotPassword.vue component,
Login.vue:
<template>
<section class="section">
<div class="container">
<div class="columns">
<div class="column"></div>
<div class="column is-half">
<div class="box">
<h1 class="title">Login</h1>
<form #submit.prevent="login">
<b-field label="Email" :message="feedback" :type="type">
<b-input placeholder="Email" icon="email" type="email" v-model="email">
</b-input>
</b-field>
<b-field label="Password" :message="feedback" :type="type">
<b-input placeholder="Password" type="password" icon="textbox-password" password-reveal v-model="password">
</b-input>
</b-field>
<button type="submit" class="button is-primary is-fullwidth">Login</button>
<div class="field">
<div class="control">
<p class="control has-text-centered">
<ForgotPassword/>
</p>
</div>
</div>
<div class="field">
<div class="control">
<p class="control has-text-centered">
Don't have an account?
<a href="/register">
<router-link :to="{ name: 'Signup' }">
Signup
</router-link>
</a>
</p>
</div>
</div>
</form>
</div>
</div>
<div class="column"></div>
</div>
</div>
</section>
</template>
<script>
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'
import ForgotPassword from '#/components/auth/ForgotPassword'
export default {
name: 'login',
metaInfo: {
// specify a metaInfo.title, this title will be used
title: 'Login',
// all titles will be injected into this template
titleTemplate: '%s | Wterdrops.com'
},
components: {
ForgotPassword
},
data () {
return {
email: null,
password: null,
feedback: null,
type: null
}
},
methods: {
login () {
if (this.email && this.password) {
firebase
.auth()
.signInWithEmailAndPassword(this.email, this.password)
.then(cred => {
this.$router.push({
name: 'Dashboard'
})
})
.catch(err => {
this.feedback = err.message
})
this.feedback = null
} else {
this.feedback = 'Please fill in both fields.'
this.type = 'is-danger'
}
}
}
}
</script>
<style>
.login {
max-width: 400px;
margin-top: 60px;
}
</style>
I would be very grateful if someone can explain to me what I'm missing :)
You are referencing
<form #submit.prevent="sendResetMail">
inside your ModalForm component.
The problem is that this template is going to look for the method sendResetMail on that ModalForm component template when it gets rendered since you the code is referencing it. However this sendResetMail method is not directly associated on that.
You can consider using a mix-in if you need to use the sendResetMail in many places , or maybe just move that method directly to the same component "ModalForm" that is referencing it.
You can also look into for example eventBus to trigger the method by emitting an event.
The simplest option if you only need to call it from the MOdalForm component is to just move the sendResetMail direcly to that component. I believe that would probably fix your issue.
I am trying to create a Vue-Routes application in which it should be possible to change colors of two divs in index.html by writing the name of the selected colors in two input fields. This is a bit complicated since this is a routes app. How do I accomplish this task?
The finished application should have this functionality: Codepen.
index.js (Routes)
import ColorPage from '../components/colorPage.js'
const routes = [
{path: '/', component: ColorPage},
];
const router = new VueRouter({
routes
});
var vm = new Vue({
el: '.container',
router,
});
ColorPage.js
const ColorPage = {
props:
['bga', 'bgb'],
data() {
bga: {
backgroundColor: ''
},
bgb: {
backgroundColor: ''
}
},
template: `
<div id="middle">
<label id="colorLabel"><h2>'Change Colors By Typing Their Names:'</h2></label>
</br>
<input type="text" class="colorInput" v-on:input="bga.backgroundColor = $event.target.value" placeholder="here...">
</br>
<input type="text" class="colorInput" v-on:input="bgb.backgroundColor = $event.target.value" placeholder="... and here!">
</div>
`,
};
export default ColorPage
Index.html
<body>
<div class="container" v-bind:style="bga">
<div class="top" v-bind:style="bgb">
<div id="app">
<h1 id="vueHead">Vue routing</h1>
<h2 class="menu">
<router-link to="/">Color</router-link>
<router-link to="/main">Main</router-link>
<router-link to="/settings">Settings</router-link>
<router-link to="/vue">Vue</router-link>
</h2>
</div>
</div>
<router-view></router-view>
</div>
</body>
You need to define bga and bgb in parent also
const ColorPage = {
props:['bga','bgb'],
template: `
<div id="middle">
<label id="colorLabel"><h2>Change Colors By Typing Their Names:</h2></label>
</br>
<input type="text" class="colorInput" v-model="$parent.bga" placeholder="here...">
</br>
<input type="text" class="colorInput" v-model="$parent.bgb" placeholder="... and here!">
</div>
`
};
const routes = [
{path: '/', component: ColorPage}
];
const router = new VueRouter({
routes
});
var vm = new Vue({
el: '.container',
router,
data:{
bga:'',
bgb:''
}
});
<script type="text/javascript" src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script type="text/javascript" src="https://unpkg.com/vue-router#2.7.0/dist/vue-router.js"></script>
<div class="container">
<div v-bind:style="bga">
<div class="top" v-bind:style="'background-color:'+bga+';'">
<div id="app">
<h1 id="vueHead" v-bind:style="'color:'+bgb+';'">Vue routing</h1>
<h2 class="menu">
<router-link to="/">Color</router-link>
<router-link to="/main">Main</router-link>
<router-link to="/settings">Settings</router-link>
<router-link to="/vue">Vue</router-link>
</h2>
</div>
</div>
<router-view></router-view>
</div>
</div>
Another way is by $parent
const ColorPage = {
data:function(){
return {
bga: this.$parent.bga,
bgb: this.$parent.bgb,
}
},
methods:{
changeBgaColor:function(){
this.$parent.bga = this.bga;
},
changeBgbColor:function(){
this.$parent.bgb = this.bgb;
}
},
template: `
<div id="middle">
<label id="colorLabel"><h2>Change Colors By Typing Their Names:</h2></label>
</br>
<input type="text" class="colorInput" v-on:keyup="changeBgaColor" v-model="bga" placeholder="here...">
</br>
<input type="text" class="colorInput" v-on:keyup="changeBgbColor" v-model="bgb" placeholder="... and here!">
</div>
`
};
const routes = [
{path: '/', component: ColorPage}
];
const router = new VueRouter({
routes
});
var vm = new Vue({
el: '.container',
router,
data:{
bga:'',
bgb:''
}
});
<script type="text/javascript" src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<script type="text/javascript" src="https://unpkg.com/vue-router#2.7.0/dist/vue-router.js"></script>
<div class="container">
<div v-bind:style="bga">
<div class="top" v-bind:style="'background-color:'+bga+';'">
<div id="app">
<h1 id="vueHead" v-bind:style="'color:'+bgb+';'">Vue routing</h1>
<h2 class="menu">
<router-link to="/">Color</router-link>
<router-link to="/main">Main</router-link>
<router-link to="/settings">Settings</router-link>
<router-link to="/vue">Vue</router-link>
</h2>
</div>
</div>
<router-view></router-view>
</div>
</div>
Unable to call logout function inside login controller. I have simple login and logout functionality using ui-router.
I am able to login and route to other page but I am not able to call logout function. I have tried all the possible solutions such as using:
<li><a href ng-click="$event.preventDefault();logout()">Logout</a></li> //only href
<li>Logout</li> //empty href
<li><a href ng-click="$event.preventDefault();logout()">Logout</a></li> //href with event
button class="btn" ng-click="logout()">Logout</button> //also button type
However, none of the above fired the logout function. I guess something wrong with scope or stateprovider.
Stateprovider:
myApp.config(function ($stateProvider, $urlRouterProvider) {
// default route
$urlRouterProvider.otherwise("/Home");
// ui router states
$stateProvider
.state('Home', {
url: "/Home",
views: {
content: {
templateUrl: 'views/HomePage.html',
controller: function ($scope) {
}
}
}
})
.state('LoggedIn', {
url: "/LoggedIn",
views: {
'content': {
templateUrl: 'views/LoggedIn.html',
controller: function ($scope) {
}
}
}
});
});
Login controller:
myApp.controller('loginController', ['$scope', '$http', 'jwtHelper', '$localStorage', '$sessionStorage', '$state', '$window', function ($scope, $http, jwtHelper, $localStorage, $sessionStorage, $state, $window)
{
$scope.loginForm = function (email, password) {
if (email !== undefined && password !== undefined) {
$http.post('rs/loginResource/login', {email: email, password: password})
.then(function (data) {
$localStorage.token = data.token;
$state.go('LoggedIn');
console.log(data.data.token);
})
.catch(function (error) {
console.log(error);
});
}
$scope.logout = function () {
alert("logout called"); //it is not firing the alert here
delete $localStorage.token;
$state.go('Home');
};
};
}]);
Index html:
<boyd>
<div id="wrap">
<div ui-view="content"></div>
</div>
</body>
Main html:
<div ng-controller="loginController">
<form class="form" method="post" ng-submit="loginForm(email, password)">
<div class="form-group">
<label class="sr-only">Email address</label>
<input type="email" ng-model="email" required>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" ng-model="password">
</div>
<div class="form-group">
<button type="submit">Sign in</button>
</div>
</form>
</div>
LoggedIn html:
<div ng-app="myApp">
<nav>
<div class="container">
<div ng-controller="loginController">
<ul>
<li><a href ng-click="logout()">Logout</a></li>
</ul>
</div>
</div>
</nav>
<h2>Logged In....</h2>
</div>
The logout function seems to be inside the loginForm function
var LandingView = Backbone.View.extend({
initialize: function() {
console.log('Landing View has been initialized');
this.render();
},
template: Handlebars.compile($('#landingPage').html()),
render: function() {
this.$el.html(this.template);
},
events: {
// I want to render the subview on click
'click .btn-login' : 'renderlogin',
},
renderlogin: function() {
// Is this the right way to instantiate a subview?
var loginpage = new LoginView({ el: $('#modal-content') });
}
});
And my next view, which basically just empties the $('#modal-content') element...
var LoginView = Backbone.View.extend({
initialize: function() {
this.render();
console.log("login view initialized");
},
template: Handlebars.compile($('#loginPage').html()),
render: function() {
this.delegateEvents();
this.$el.html(this.template);
},
events: {
// this is where things get super confusing...
// Upon clicking, LoginView gets re-initialized and
// subsequent clicks are called for each number of times
// the view is initialized.
'click .js-btn-login' : 'login'
},
login: function(e) {
e.preventDefault();
var self = this;
console.log($(this.el).find('#userSignIn #userEmail').val());
console.log($(this.el).find('#userSignIn #userPassword').val());
}
});
My templates:
LANDING PAGE:
<script type="text/x-handlebars-template" id="landingPage">
<div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<div class="to-auth-buttons-wrapper">
<a class="btn-to-auth btn-signup" href="#">Sign Up</a>
<a class="btn-to-auth btn-login" href="#">Log In</a>
</div>
</div>
</div>
</script>
LOGINPAGE:
<script type="text/x-handlebars-template" id="loginPage">
<div>
<div class="header">
Back
</div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<form method="post" id="userSignIn">
<input class="form-control input-signin" type="text" name="useremail" placeholder="Email" id="userEmail" value="tester">
<input class="form-control input-signin" type="password" name="userpass" placeholder="Password" id="userPassword">
<button class="btn-to-auth btn-login js-btn-login">Log In</button>
</form>
</div>
</div>
</script>
My goal:
From within LandingView, upon clicking .btn-login, render LoginView.
From within LoginView, upon clicking .js-btn-login, console.log
contents of form
Problems:
In LoginView, upon clicking .js-btn-login, I see that the initialize function is called again.
In LoginView, I can't use jquery to get the values inside of $('#userSignIn #userEmail').val() and $('#userSignIn #userEmail').val() because they aren't there on render. I see the initial hardcoded value ( input[value="tester"]) but this is all it sees.
My question:
How do I get the view to stop reinitializing on an event firing and how do I get the values in my DOM after rendering?
I've got an app with 3 pages which I'm trying to render on click. The first page is a landing page. The other two should be rendered upon clicking a link. They are all contained inside of the same container div#modal-content
My HTML is as follows:
<script type="text/x-handlebars-template" id="landingPage">
<div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<div class="to-auth-buttons-wrapper">
<a class="btn-to-auth btn-login" href="#signup-page">Sign Up</a>
<a class="btn-to-auth btn-signup" href="#login-page">Log In</a>
</div>
</div>
</div>
</script>
My router function is as follows:
var Approuter = Backbone.Router.extend({
initialize: function() {
console.log('router initialized');
Backbone.history.start({ pushState: true });
},
routes: {
'': 'main',
'signup-page' : 'signup',
'login-page' : 'login'
},
main: function() {
this.landing = new LandingView({ el: $('#modal-content') });
slider.slidePage(this.landing.$el);
},
signup: function() {
this.signuppage = new SignUpView({ el: $('#modal-content') });
console.log("LANDING VIEW: Signup clicked");
},
login: function() {
this.loginpage = new LoginView({ el: $('#modal-content') });
console.log("LANDING VIEW: Login clicked");
}
});
And the view files are as follows:
var SignUpView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function() {
var template = Handlebars.compile($('#signUpPage').html());
this.$el.html(template);
},
});
and
var LoginView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function() {
var template = Handlebars.compile($('#loginPage').html());
this.$el.html(template);
},
});
Additionally, here are my templates:
<div id="modal-content">
<script type="text/x-handlebars-template" id="landingPage">
<div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<div class="to-auth-buttons-wrapper">
<a class="btn-to-auth btn-login" href="#/signup-page">Sign Up</a>
<a class="btn-to-auth btn-signup" href="#/login-page">Log In</a>
</div>
</div>
</div>
</script>
<script type="text/x-handlebars-template" id="signUpPage">
<div>
<div class="header">
Back
</div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<form method="post" id="userSignUp">
<input class="form-control input-signin" type="text" name="username" placeholder="Name" id="userName">
<input class="form-control input-signin" type="text" name="useremail" placeholder="Email" id="userEmail">
<input class="form-control input-signin" type="text" name="userpass" placeholder="Password" id="userPassword">
<a class="btn-to-auth btn-login js-btn-login">Sign Up</a>
</form>
</div>
</div>
</script>
<script type="text/x-handlebars-template" id="loginPage">
<div>
<div class="header">
Back
</div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<form method="post" id="userSignIn">
<input class="form-control input-signin" type="text" name="useremail" placeholder="Email" id="userEmail">
<input class="form-control input-signin" type="password" name="userpass" placeholder="Password" id="userPassword">
<a class="btn-to-auth btn-login js-btn-login">Log In</a>
</form>
</div>
</div>
</script>
</div>
My Problem
Upon clicking the a#signup-page or a#login-page links, I can see the url change to "localhost/#signup-page", but the view is not being rendered.
BUT
When I refresh the page at localhost/#signup-page or localhost/#login-page, I see the views are rendered.
Where am I going wrong?
Please take a look at the code above:
<html>
<body>
<div class="action">
<a name="routeOne" href="#routeTwo">routeOne</a>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<a name="routeTwo" href="#routeOne">routeTwo</a>
</div>
<div class="output"></div>
<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="lib/underscore.js"></script>
<script type="text/javascript" src="lib/backbone.js"></script>
<script type="text/javascript">
var Approuter = Backbone.Router.extend({
initialize: function() {
console.log('router initialized');
Backbone.history.start({pushState:true});
},
routes: {
'': 'main',
'routeOne' : 'routeOne',
'routeTwo' : 'routeTwo'
},
main: function() {
console.log("main");
},
routeOne: function() {
console.log("routeOne");
},
routeTwo: function() {
console.log("routeTwo");
}
});
var routes = new Approuter();
</script>
</body>
</html>
Edit1: Differences between Routes and pushState
Backbone Routes enable you to monitoring hasChange history events (changes in url) and trigger some js code when found some change at url (http://localhost/backbone-test/#someRoute), That's amazing because we can trigger some complex actions done by user at your web site, just calling an url.
pushState enable you to hide this '#' hash and turn your url more readable, but as the backbone documentation said
"if you have a route of /documents/100, your web server must be able
to serve that page, if the browser visits that URL directly."
Then, if you use pushState:true your url become more readable, http://localhost/backbone-test/#someRoute to http://localhost/backbone-test/someRoute but you need to create a back-end to answer directly access to you readable url.
When pushState is true and you call href="#someRoute" the browser understand this as a html anchor.