How to Render Data to the DOM using vue-cli - templates

I have created a template:
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow: function() {
this.isShowing = !this.isShowing;
setTimeout(() => {
this.toggleShow1();
}, 800);
}
}
<script>
<style>
..
</style>
And in the HTML document i'd like to toggle a heading only when isShowing is set to true:
<div v-if="isShowing">
<div>
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h1>
</div>
</div>
But then i get this error: ReferenceError: isShowing is not defined
Any help would be much appreciated. Thanks!

You're using a data of vue instance outside of itself. isShowing can only be used inside the <template> of the same .vue file.
For example:
<template>
<div>
<div v-if="isShowing">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow: function() {
this.isShowing = !this.isShowing;
setTimeout(() => {
this.toggleShow1();
}, 800);
}
}
<script>
<style>
..
</style>

Related

How do I detect change Sveltekit state

I am trying to add a class to an element in one component (nav) when an animation in a different component (logo) ends. In my $lib/Logo.svelte file I have the following code:
<script>
import { onMount } from 'svelte';
import { isLogoAnimationEnded } from './stores';
onMount(() => {
const body = document.querySelector('body');
const h1 = document.querySelector('.name');
h1?.addEventListener('animationend', () => {
isLogoAnimationEnded.update((n) => (n = true));
console.log($isLogoAnimationEnded);
body?.classList.add('shake');
});
return () => {
h1?.removeEventListener('animationend', () => {
isLogoAnimationEnded.set(false);
body?.classList.remove('shake');
});
};
});
</script>
<div class="logo-wrapper">
<h1 class="name">Tim Smith</h1>
<p class="title">Full Stack Web Engineer</p>
</div>
<style>
...
</style>
My
store is defined in $lib/stores.js:
import { writable } from 'svelte/store';
export const isLogoAnimationEnded = writable(false);
What I am trying to do is listen for a change in isLogoAnimationEnded in $lib/Nav.svelte and add a class to nav when isLogoAnimationEnded becomes true.
<script lang="ts">
import { onMount } from 'svelte';
import { isLogoAnimationEnded } from './stores';
let nav;
onMount(() => {
nav = document.querySelector('nav');
console.log('nav', nav);
});
if ($isLogoAnimationEnded) {
nav?.classList.add('fly-down');
}
</script>
<div class="nav-wrapper">
<nav aria-label="Main">
<ul>
<li>About</li>
<li>Projects</li>
<li>Contact</li>
</ul>
</nav>
</div>
<style>
...
</style>
My current setup does not work. Please help.
The code below is only going to run once
if ($isLogoAnimationEnded) {
nav?.classList.add('fly-down');
}
So I would delete it and write the class attribute on nav element like this:
<nav class={$isLogoAnimationEnded ? "fly-down" : ""} aria-label="Main">
This also gets rid of the onMount, nav variable and querySelector

Vue.js - Vuetify - Hard time to test a menu component

Given the following Toolbar component, I am trying to test the locale changing upon click on menu item ... but the wrapper content is not changing after a mouseover event on the menu selector ...
Toolbar.vue
<template>
<v-toolbar height="80px" fixed>
<v-toolbar-title>
<img src="#/assets/images/app_logo.png" alt="">
<v-menu bottom offset-y open-on-hover class="btn btn--flat" style="margin-bottom: 12px;">
<v-btn id="current-flag" flat slot="activator">
<img :src="flagImage(currentLocaleIndex)" width="24px">
</v-btn>
<v-list>
<v-list-tile v-for="(locale, index) in locales" :key="index" #click="switchLocale(index)">
<div class="list__tile__avatar avatar--tile" #click="switchLocale(index)">
<img :src="flagImage(index)" width="24px">
</div>
<div class="list__tile__title" v-html="flagTitle(index)"></div>
</v-list-tile>
</v-list>
</v-menu>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<!-- MENU HOME-->
<v-btn flat #click="$router.push(menuItems.home.link)">
<v-icon left>{{ menuItems.home.icon }}</v-icon>
<span>{{ menuItems.home.title | translate }}</span>
</v-btn>
<!-- ABOUT HOME-->
<v-btn flat #click="$router.push(menuItems.about.link)">
<v-icon left>{{ menuItems.about.icon }}</v-icon>
<span>{{ menuItems.about.title | translate }}</span>
</v-btn>
</v-toolbar-items>
</v-toolbar>
</template>
<script>
// import i18n from '#/locales'
export default {
name: "Toolbar",
props: ["appName"],
data() {
return {
menuItems: {
home: { icon: "home", title: "Home", link: "/" },
about: { icon: "info", title: "About", link: "/about" }
},
locales: [
{ id: "en", title: "English", flag: "#/assets/images/flag_en_24.png" },
{ id: "fr", title: "Français", flag: "#/assets/images/flag_fr_24.png" },
{ id: "br", title: "Português", flag: "#/assets/images/flag_br_24.png" }
]
};
},
computed: {
currentLocaleIndex: function() {
let index = this.locales.findIndex(o => o.id === this.$i18n.locale);
return index;
},
currentLocaleTitle: function() {
let obj = this.locales.find(o => o.id === this.$i18n.locale);
return obj.title;
},
currentLocaleFlag: function() {
let obj = this.locales.find(o => o.id === this.$i18n.locale);
return obj.flag;
}
},
methods: {
flagImage: function(index) {
return require("#/assets/images/flag_" +
this.locales[index].id +
"_24.png");
},
flagTitle: function(index) {
return this.locales[index].title;
},
switchLocale: function(index) {
this.$i18n.locale = this.locales[index].id;
}
},
mounted() {}
};
</script>
Toobar.spec.je
import Vue from "vue";
import router from "#/router";
import Vuetify from "vuetify";
import i18n from "#/locales";
import { mount, shallowMount } from "#vue/test-utils";
import Toolbar from "#/components/shared/Toolbar.vue";
describe("App.vue", () => {
let wrapper;
beforeEach(() => {
Vue.use(Vuetify);
Vue.filter("translate", function(value) {
if (!value) return "";
value = "lang.views.global." + value.toString();
return i18n.t(value);
});
const el = document.createElement('div');
el.setAttribute('data-app', true);
document.body.appendChild(el);
});
it("should change locale", () => {
// given
wrapper = mount(Toolbar, { router, i18n });
console.log('CURRENT LOCALE INDEX: ', wrapper.vm.currentLocaleIndex);
// console.log(wrapper.html());
const currentFlagBtn = wrapper.find("#current-flag");
console.log(currentFlagBtn.html())
currentFlagBtn.trigger('mouseover');
wrapper.vm.$nextTick( () => {
console.log(wrapper.html());
// const localesBtn = wrapper.findAll("btn");
});
// when
// localesBtn.at(1).trigger("click"); // French locale
// then
// expect(wrapper.wrapper.vm.currentLocaleIndex).toBe(1);
});
});
console.log
console.log tests/unit/Toolbar.spec.js:32
CURRENT LOCALE INDEX: 0
console.log tests/unit/Toolbar.spec.js:35
<button type="button" class="v-btn v-btn--flat" id="current-flag"><div class="v-btn__content"><img src="[object Object]" width="24px"></div></button>
console.log tests/unit/Toolbar.spec.js:38
<nav class="v-toolbar v-toolbar--fixed" style="margin-top: 0px; padding-right: 0px; padding-left: 0px; transform: translateY(0px);">
<div class="v-toolbar__content" style="height: 80px;">
<div class="v-toolbar__title">
<img src="#/assets/images/app_logo.png" alt="">
<div class="v-menu btn btn--flat v-menu--inline" style="margin-bottom: 12px;">
<div class="v-menu__activator">
<button type="button" class="v-btn v-btn--flat" id="current-flag">
<div class="v-btn__content">
<img src="[object Object]" width="24px">
</div>
</button>
</div>
</div>
</div>
<div class="spacer"></div>
<div class="v-toolbar__items">
<button type="button" class="v-btn v-btn--flat">
<div class="v-btn__content">
<i aria-hidden="true"class="v-icon v-icon--left material-icons">home</i>
<span>Home</span>
</div>
</button>
<button type="button" class="v-btn v-btn--flat">
<div class="v-btn__content">
<i aria-hidden="true" class="v-icon v-icon--left material-icons">info</i>
<span>About</span>
</div>
</button>
</div>
</div>
</nav>
I found a solution, but maybe someone can explain why :
btnFlags.at(1).vm.$emit('click'); // OK
and
btnFlags.at(1).trigger('click'); // NOT OK
this is the spec which is running fine :
import Vue from "vue";
import router from "#/router";
import Vuetify from "vuetify";
import i18n from "#/locales";
import { mount, shallowMount } from "#vue/test-utils";
import Toolbar from "#/components/shared/Toolbar.vue";
describe("Toolbar.vue", () => {
let wrapper;
beforeEach(() => {
Vue.use(Vuetify);
Vue.filter("translate", function(value) {
if (!value) return "";
value = "lang.views.global." + value.toString();
return i18n.t(value);
});
const el = document.createElement('div');
el.setAttribute('data-app', true);
document.body.appendChild(el);
});
it("should change locale", async () => {
// given
wrapper = shallowMount(Toolbar, { router, i18n });
console.log('CURRENT LOCALE INDEX: ', wrapper.vm.currentLocaleIndex);
const btnFlags = wrapper.findAll("v-list-tile-stub");
// when
btnFlags.at(1).vm.$emit('click');
await wrapper.vm.$nextTick();
// then
console.log('NEW LOCALE INDEX: ', wrapper.vm.currentLocaleIndex);
expect(wrapper.vm.currentLocaleIndex).toBe(1);
});
});

Vue.js Vuex Unit test on user input, can I consider my test OK when coverage is 100%

I am currently testing one of my children components
I already tested successfully all vuex actions, mutations and getters
When I run this ChangeTitleComonent.spec.js , it passes with 100% coverage.. thanks for feedback
Do I need to write some additional tests when it's 100% covered ? or is this test bad written ?
PARENT
ShoppingListComponent.vue
<template>
<div>
<h2>{{ title }}</h2>
<add-item-component :id='id' #add="addItem"></add-item-component>
<items-component :items="items" :id="id"></items-component>
<div class="footer">
<hr />
<change-title-component :title="title" :id="id"></change-title-component>
</div>
</div>
</template>
<script>
import AddItemComponent from './AddItemComponent'
import ItemsComponent from './ItemsComponent'
import ChangeTitleComponent from './ChangeTitleComponent'
export default {
components: {
AddItemComponent,
ItemsComponent,
ChangeTitleComponent
},
props: ['id', 'title', 'items'],
methods: {
addItem (text) {
this.items.push({
text: text,
checked: false
})
}
}
}
</script>
<style scoped>
.footer {
font-size: 0.7em;
margin-top: 20vh;
}
</style>
CHILDREN
ChangeTitleComponent
<template>
<div>
<em>Change the title of your shopping list here</em>
<input :value="title" #input="onInput({ title: $event.target.value, id: id })"/>
</div>
</template>
<style scoped>
</style>
<script>
import { mapActions } from 'vuex'
export default {
props: ['title', 'id'],
methods: mapActions({ // dispatching actions in components
onInput: 'changeTitle'
})
}
</script>
UNIT TEST
ChangeTitleComponent.spec.js
import Vue from 'vue'
import ChangeTitleComponent from '#/components/ChangeTitleComponent'
import store from '#/vuex/store'
describe('ChangeTitleComponent.vue', () => {
describe('changeTitle', () => {
var component
beforeEach(() => {
var vm = new Vue({
template: '<change-title-component :title="title" :id="id" ref="changetitlecomponent">' +
'</change-title-component></div>',
components: {
ChangeTitleComponent
},
props: ['title', 'id'],
store
}).$mount()
component = vm.$refs.changetitlecomponent
})
it('should change the title', () => {
// check component label text
expect(component.$el.textContent).to.equal('Change the title of your shopping list here ')
// simulate input Enter event
const input = component.$el.querySelector('input')
input.value = 'My New Title'
const enterEvent = new window.Event('keypress', { which: 13 })
input.dispatchEvent(enterEvent)
component._watcher.run()
})
})
})

My Bootstrap Modal is Not hiding after Successful Login,Got Stuck

I got stuck at this javascript code,why it is not working ,I used a static backdrop bootstrap model for login,after successful login ,i want to hide the model in success callback function but the model is not hiding,the Page is still there,don't know what i am doing wrong
enter image description here
Myjs File
$(document).ready(function () {
$('#myModal').modal({
backdrop: 'static',
});
});
function Login() {
var dataobject = { Social_Security_Number: $('#Social_Security_Number').val(), Lumik_Id: $('#Lumik_Id').val() };
// var dataobject = { Social_Security_Number:"123456789", Lumik_Id: "sgupta8" };
$.ajax({
url: '/User/Login',
type: "POST",
data: dataobject,
dataType: "json",
success: function (result) {
if (result.toString == "Success") {
$('#myModal').modal('hide');
//redirecttoPage()
}
},
error: function (result) {
alert('Error');
}
})
}
UserController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using login.Models;
namespace login.Controllers
{
public class UserController : Controller
{
UserBusinessLogic obj = new UserBusinessLogic();
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(User user)
{
string message = "";
if (ModelState.IsValid)
{
if (obj.checkuserlogin(user) > 0)
{
message = "Success";
}
else
{
message = "Username or Password is wrong";
}
}
else {
message = "ALL FIELDS ARE REQUIRED";
}
if (Request.IsAjaxRequest())
{
return Json(message, JsonRequestBehavior.AllowGet);
// return RedirectToAction("Profile", "User", new { #name = result });
}
else
{
return RedirectToAction("Index", "Home");
}
}
public ActionResult Profile(string name)
{
return View();
}
}
}
Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
</head>
#*<script src="../../Scripts/jquery-1.9.1.js"></script>*#
<script src="../../Scripts/jquery-1.9.1.min.js"></script>
<script src="../../Scripts/Myfile.js"></script>
<link href="../../Scripts/bootstrap.min.css" rel="stylesheet" />
<script src="../../Scripts/bootstrap.min.js"></script>
<body>
#RenderBody()
</body>
Login.cshtml
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<form class="form-horizontal">
<div class="modal-header">
</div>
<br />
<div class="form-group">
<label for ="Social_Security_Number" class="col-lg-3 control-label"></label>
<input class="form-control" id="Social_Security_Number" placeholder="Social Security Number" type="text" />
</div>
<div class="form-group">
<label for="Lumik_Id" class="col-lg-3 control-label"></label>
<input class="form-control" id="Lumik_Id" placeholder="Lumik Id" type="text" />
</div>
<div class="modal-footer">
<input type="button" value="Login" class="btn btn-primary" onclick="Login()" />
</div>
</form>
</div>
</div>
</div>
<style>
.modal-dialog {
max-width:480px;
}
.modal-dialog {
transform:translate(0,58%) !important;
-as-transform:translate(0,58%) !important;
-webkit-transform:translate(0,58%) !important;
}
.RbtnMargin {
margin-left:90px;
}
</style>
Could you try : $(document).find('#myModal').modal('hide'); instead of $('#myModal').modal('hide');
Reason is : your data added dynamically.
Let me know.

Getting to know Ember StateManager, am I coding this right?

I am getting my feet wet with Ember.JS StateManager, and I am currently following the online documentation at: http://emberjs.com/api/classes/Ember.StateManager.html
I have done my best with this fiddle but cannot seem to get anything visual out at all. I have done numerous searches here at SOF and Google.
I have three states with three list item which trigger these states in view. I have placed a "ready function" within "Application.create({}" which fires, but as soon as the StateManager is initialized, "ready function" doesn't fire. I would highly appreciate your input and help.
Here is the fiddle: http://jsfiddle.net/exciter/NRmHc/12/
APP CODE
$(function(){
App = Ember.Application.create({
ready: function(){
//alert("APP INIT");
}
});
App.stateManager = Ember.StateManager.create({
showFirstState: function(manager){
App.stateManager.transitionTo('startupState');
},
showSecondState: function(manager){
App.stateManager.transitionTo('second');
},
showThirdState: function(manager){
App.stateManager.transitionTo('third');
},
showFourthState: function(manager){
App.stateManager.transitionTo('fourth');
},
// INIT STATE
initialState: 'startupState',
startupState: Ember.State.create({
templateName: 'startup',
classNames: ['state','black'],
enter: function() { alert("STARTUP ENTERED"); }
}),
second: Ember.State.create({
templateName: 'second',
classNames: ['state','orange'],
enter: function() { alert("SECOND ENTERED"); }
}),
third: Ember.State.create({
templateName: 'third',
classNames: ['state','lime'],
enter: function() { alert("THIRD ENTERED"); }
}),
fourth: Ember.State.create({
templateName: 'fourth',
classNames: ['state','blue'],
enter: function() { alert("FOURTH ENTERED"); }
}),
});
App.initialize();
});
HTML:
<!-- CHECK TO SEE IF CSS IS FUNCTIONAL
<div id="state" class="state blue">
STATE
</div>
-->
<script type="text/x-handlebars">
<nav>
<ul>
<li {{action "showFirstState" target="App.stateManager"}}>First State</li>
<li {{action "showSecondState" target="App.stateManager"}}>Second State</li>
<li {{action "showThirdState" target="App.stateManager"}}>Third State</li>
<li {{action "showFourthState" target="App.stateManager"}}>Fourth State</li>
</ul>
</nav>
</script>
<script type="text/x-handlebars" data-template-name="startup">
<h2> STARTUP STATE </h2>
</script>
<script type="text/x-handlebars" data-template-name="second">
<h2>SECOND STATE</h2>
</script>
<script type="text/x-handlebars" data-template-name="third">
<h2>THIRD STATE</h2>
</script>
<script type="text/x-handlebars" data-template-name="fourth">
<h2>THIRD STATE</h2>
</script>
CSS:
nav { background-color:#e9e9e9; padding: 1em 0 1em 0; }
nav li { display: inline; cursor: pointer; padding:0 1em 0 1em;}
.state { width:700px; height:500px; margin:0 auto; padding:0; background-color:#c9c9c9; }
.black { background-color:#666; }
.blue { background-color:#6699cc; }
.orange { background-color:#FF6600; }
.lime { background-color:#CCFF33; }
I get the feeling that what you want is not a statemanager but a router. Have a look at this link for further info.