Custom element not working, however not giving me an error - javascript

I'm making a custom element for my website. I made 2 elements, the 2nd one works however the first one doesn't. Here are the 2 elements:
class Popup extends HTMLElement {
connectedCallback() {
this.dataset.rating = 1; /*document.querySelector("rating-inter").dataset.rating*/
console.log("Debug: tenplate");
this.template = `
<!-- Thank you state start -->
<p class="typog">
You selected ${this.dataset.rating} out of 5
</p>
<h1>
Thank you!
</h1>
<p>
We appreciate you taking the time to give a rating. If you ever need more support, don’t hesitate to get in touch!
<!-- Thank you state end -->
</p>
`
this.ele = document.createElement("div")
this.ele.innerHTML = this.ele
this.appendChild(this.ele)
}
}
class Rating extends HTMLElement {
connectedCallback() {
this.template = `
<div class="star">
<img class="star" src="images/icon-star.svg" alt="Star">
</div>
<!-- Rating state start -->
<h1>
How did we do?
</h1>
<p class="typog">
Please let us know how we did with your support request. All feedback is appreciated
to help us improve our offering!
</p>
<div class="btns">
<button class="numbers">1</button> <button class="numbers">2</button>
<button class="numbers">3</button> <button class="numbers">4</button>
<button class="numbers">5</button>
</div>
<div id="submit">
<button id="submitBtn">Submit</button>
</div>
<!-- Rating state end -->
`
this.ele = document.createElement("div")
this.ele.innerHTML = this.ele
this.appendChild(this.ele)
this.dataset.rating = null
}
}
The first one simply gives me a blank view, with no error message. I can't tell why this is happening. No console.log() inside of the connectedCallback work

Related

How to dynamically add a component on link click in my Angular application

I have three components: (1) a navigation bar, (2) home page with a left and right div, and (3)view-associates. On link from the navbar, I want to dynamically add the view-associates component into the home's right div. I have already implemented the following code (in the traditional JavaScript fashion) into the navbar-component.ts file:
addTemplateTag(){
const link = document.querySelector('.nav-link');
const showArea = document.getElementById('showArea');
console.log(link);
console.log(showArea);
// check for specific class name to get appropriate template tag
if (link.classList.contains('view-associates')){
console.log('Found view-associates class in link. Getting tag...');
// NOTE: the below two lines did work BUT still did not show component
const templateTag = document.createElement('app-view-associates');
showArea.appendChild(templateTag);
}
}
Here is the HTML code with the navbar and home components, respectively:
navbar.component.html
<nav class="nav flex-column">
<a class="nav-link view-associates" (click)="addTemplateTag()">View My Associates</a>
</nav>
home.component.html (Before link click)
<div class="container-fluid">
<div class="float-left left">
<h1 class="title">Welcome</h1>
<app-nav-bar></app-nav-bar>
<button class="btn btn-primary logout-btn" (click)="logOut()">Log Out</button>
</div>
<div id="showArea" class="float-left right">
</div>
</div>
home.component.html (After link click)
<div class="container-fluid">
<div class="float-left left">
<h1 class="title">Welcome</h1>
<app-nav-bar></app-nav-bar>
<button class="btn btn-primary logout-btn" (click)="logOut()">Log Out</button>
</div>
<div id="showArea" class="float-left right">
<app-view-associates></app-view-associates>
<-- ^^^ appended but component not showing -->
</div>
</div>
Here's the images of the home page before and after the link click:
Before (with browser console)
After (with browser console)
This above code did work but still did not show the view-associates component at all. How do I resolve this issue? Any advice is appreciated.
Use ngIf and ngSwitch to show/ hide components dynamically. For example : -
in .html
<app-form></app-form>
<some-component *ngIf="isLoggedIn"></some-component>
<some-component *ngIf="!isWorking"></some-component>
<another-cool-component *ngIf="!isLoggedIn"></another-cool-component>
in .ts
export class MyFunnyComponent implements OnInit {
isLoggedIn = false;
cartValue: number;
constructor() {
}
ngOnInit(): void {
}
}
Obviously there are some other ways to handle these scenarios but, for the start it might be enough. We might also have to pass data from child to parent and vise versa.

Random Quote Machine - Cant tweet quote

I have to tweet a quote that I randomly generated using APIs, but my code isn't working. Here is my code, I added comments trying to make it look clearer. I am a novice in coding so it probably has a terrible sintax.
I manage to get my quote by clicking on the "Get another quote" button, but when i want to tweet my quote, clicking on the "Tweet quote" button it wont work and i get the "Uncaught ReferenceError: data is not defined
at pen.js:10" error.
I dont know what i am doing wrong.
(This is a task for FreeCodeCamp). Thanks to everyone who will answer!
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet" type="text/css">
<h2 class="title">Random Quote Generator</h2>
<h4 class="subtitle">A project for the FreeCodeCamp challenge</h4>
<div class="container-box">
<div class="container-quote">
<p class="quote" id ="quote"></p>
<div class="container-author" id="author">
<p></p>
</div> <!--closing div for container author-->
<div class="row">
<div class="col-md-6">
<button id="tweetQuote" href="https://twitter.com/intent/tweet?text=data.quoteText">Tweet this quote!</button>
</div>
<div class="col-md-6">
<button id="newQuote">Get another quote</button>
</div>
</div> <!--row-->
</div> <!--closing div for container quote-->
</div> <!--closing div for container-->
And now the javascript
//setting html elements to variables
var $newQuote = $('#newQuote');
var $quote = $('#quote');
var $tweetQuote = $('#tweetQuote');
//execute function by clicking on button
$newQuote.click(getQuote);
$tweetQuote.click(tweetIt);
var text = data.quoteText;
var author = data.quoteAuthor;
//when getQuote is called call the APIs and get the quote by executing
getQuoteFromAPI
function getQuote() {
$quote.empty();
getQuoteFromAPI();
};
function getQuoteFromAPI() {
var url='https://api.forismatic.com/api/1.0/?
method=getQuote&format=jsonp&lang=en&jsonp=?';
//when the APIs are completely called execute the parseQuote function
$.getJSON(url).done(parseQuote);
//log the datas on the console and transform them into real html elements
function parseQuote (response) {
console.log(response);
document.getElementById('quote').innerHTML = response.quoteText;
document.getElementById('author').innerHTML = response.quoteAuthor;
};
};
function tweetIt() {
var url='https://api.forismatic.com/api/1.0/?
method=getQuote&format=jsonp&lang=en&jsonp=?';
$('#tweetQuote').attr('href', 'https://twitter.com/intent/tweet?text=' + text + '-' + author);
};

Vue.js can't find element using querySelector

I am trying to create a chat style form. So a user inputs their data and then uses the button within my template with the class of continue-btn.
As you can see when the continue-btn is pressed it uses the nextStep method which adds 1 to the counter data property.
Within my template I then use v-if="counter >= 1" to display the next section of the chat dialog and input field.
I am then trying to use scrollTop to automatically scroll the page to the new section with the id of #conversation__tram-1. I originally tried running this block of code just after the counter had been given a value of 1:
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
This didn't work though because I'm guessing the #conversation__tram-1 element hadn't been added to the DOM yet.
So for the sake of testing I tried wrapping it in a timeout function:
setTimeout(function(){
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
}, 3000);
However I am left with this error when trying this:
Uncaught TypeError: Cannot read property 'querySelector' of undefined
Here is my whole single vue file:
<template>
<div id="conversation-app">
<!-- <div v-for="item in items">
{{ item.text }}
</div> -->
<div class="conversation__track">
<div id="conversation__tram-0">
<div class="conversation__item agent">
<img src="/assets/cdn.annuityadvicecentre.dev/images/theme-f/michael-chat-agent.jpg" class="conversation__item-prof-img" alt="Michael Chat Agent" />
<div class="conversation__item-content">
<p>
Hello my name is {{ agent }}, we'll compare the whole annuity market to bring you back the best annuity rates from the top providers for you. Let's get started, what's your name?
</p>
</div>
</div>
<div class="conversation__item customer" id="title-fullname">
<div class="conversation__item-content">
<p>
Hi {{ agent }}, my name is...
</p>
<div class="row">
<div class="col-4">
<select id="title" class="field-title" name="payload[title]"><option value="mr">Mr</option><option value="mrs">Mrs</option><option value="miss">Miss</option><option value="ms">Ms</option></select>
</div>
<div class="col-8">
<input v-model="customerName" id="full_name" class="field-full_name" name="payload[full_name]" type="text">
</div>
</div>
</div>
</div>
</div>
<transition name="fade">
<div id="conversation__tram-1" v-if="counter >= 1">
<div class="conversation__item agent">
<img src="/assets/cdn.annuityadvicecentre.dev/images/theme-f/michael-chat-agent.jpg" class="conversation__item-prof-img" alt="Michael Chat Agent" />
<div class="conversation__item-content">
<p>
Thanks {{ firstName }}, nice to meet you. To process your instant quote please can I have your Pension Value?
</p>
</div>
</div>
<div class="conversation__item customer">
<div class="conversation__item-content">
<p>
Sure, my pension value is...
</p>
<input id="pension_value" class="field-pension_value" placeholder="£" pattern="\d*" name="payload[pension_value]" type="number">
<div class="error-wrap error_pension_value is-hidden" data-format="<div class="error-text">:message</div>"></div>
</div>
</div>
</div>
</transition>
<div id="conversation__buttons">
<button type="button" class="continue-btn"
v-on:click="nextStep"
>Continue <i class="fa fa-chevron-right" aria-hidden="true"></i></button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'conversation-app',
data () {
return {
agent: 'Brick',
counter: 0,
customerName: '',
}
},
methods: {
nextStep: function() {
this.counter += 1;
setTimeout(function(){
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
}, 3000);
},
},
computed: {
firstName() {
return this.customerName.split(' ')[0];
}
}
}
</script>
Any idea why this isn't working? Thanks.
This is a good time to use arrow functions, as they preserve the context of this.
nextStep: function() {
this.counter += 1;
setTimeout(() => {
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
}, 3000);
Altenatively, instead of the timeout you can use Vue.nextTick which is a more technically-correct way of doing this.
nextStep: function () {
this.counter += 1
this.$nextTick(() => { ... })

I have a 100 button, click each button to display its corresponding bomb box, With javascript and angular

a button corresponding to a prompt box,each box is different shells;Although implements the desired function, but my code is too complicated, and that there is no simple way. how can I do? This is my code
<--html button-->
button1
button2
...
button100
<--html pop box-->
<div class="note1" style="display:none;">
<img class="title-css" src="note1.png">
<p class="one">note1</p>
</div>
...
<div class="note100" style="display:none;">
<img class="title-css" src="note100.png">
<p class="one">note100</p>
</div>
<--angular js-->
$scope.showRulePop = function(index) {
for(var i=1;i<=8;i++) {
$('.note'+i).hide();
}
$('.note'+index).show();
};
Well first of all, don't use jQuery, unless your in the directive level of angular jQuery have nothing to do there.
First let's get rid of the links part using a simple ng-repeat :
<--html button-->
<div ng-repeat="button in buttons">
{{button.label[i]}}
</div>
// JS in the controller
$scope.buttons = [{
label:'button1'
},{label:'button2'}];
As you can see i declare in the javascript all your buttons and i just loop over it.
Now the "bombox" or whatever it is let's make it a simple template :
<div class="{{currentnote.class}}" ng-if="currentNote">
<img class="title-css" src="{{currentNote.img}}">
<p class="one">{{currentNote.content}}</p>
</div>
// and use ng-repeat for the eight first when there is no button selected
<!-- show 1 to 8 if note current note selected -->
<div ng-repeat="button in buttons1To8" ng-if="!currentNote">
<div class="{{button.note.class}}">
<img class="title-css" src="{{button.note.img}}">
<p class="one">{{button.note.content}}</p>
</div>
</div>
// JS
$scope.buttons = [{
label:'button1'
note:{class:'note1', img:'note1.png', content:'note1'//assuming no HTML or you' ll need something more
}},{label:'button2', note:{...}}, ...];
$scope.showRulePop = function(index){
$scope.currentNote = $scope.buttons[index].note;
}
$scope.buttons1To8 = $scope.buttons.slice(0, 8);//0 to 7 in fact
That's all, no need of jQuery.

Hide video when clicked on any other element but itself

I am loading a video in the DOM using a directive named load-video when the displayVideo property is true.
<figure id = "positionVideo" ng-show = "displayVideo">
<load-video></load-video>
</figure>
loadVideo directive:
angular.module('homePage')
.directive('loadVideo', function($document, $window) {
return {
restrict: 'E',
templateUrl: 'partials/video/video.html',
link: function(scope, element) {
element.data('loadVideo',true);
angular.element($document[0].body).on('click',function(e) {
var inElem = angular.element(e.target).inheritedData('loadVideo');
if (inElem) {
scope.displayVideo = true;
} else {
scope.displayVideo = false;
}
})
}
};
});
video.html
<video height = "50%" width = "150%" id = "playVideo" ng-click="playIt()" poster = "images/eagle.jpg" controls>
<source src = "images/lion.mp4" type = "video/mp4">
</video>
The figure tag has access to this controller:
angular.module('homePage').controller('watchVideo', ['$scope', '$location', function($scope, $location) {
$scope.displayVideo = false;
$scope.videoAvailable = function () {
$scope.displayVideo = true;
};
$scope.closeVideo = function() {
$scope.displayVideo = false;
};
$scope.playIt = function() {
if (jQuery("#playVideo").get(0).paused) {
jQuery("#playVideo").get(0).play();
}
else {
jQuery("#playVideo").get(0).pause();
}
}
}]);
I do not understand why the video element is not hiding when I am changing the displayVideo property to false.
I am providing my entire application below for context:
<div class="firstView" ng-controller = "watchVideo">
<figure class="logo" ng-controller = "logo" ng-click="goToUrl('/home')"> </figure>
<cite>Every brand has a story.</cite>
<h2 id = "h2Heading"> <a ng-click = "videoAvailable()">Watch the video </a></h2>
<aside> → </aside>
<figure id = "positionVideo" ng-show = "displayVideo">
<load-video></load-video>
</figure>
<summary ng-controller = "buttonViewCtrl">
<button type="button" ng-hide = "buttonDisplay" ng-show = "!displayVideo" class="btn btn-default btn-lg navButton" aria-label="Center Align" ng-click="nav()">
<span class="glyphicon glyphicon-align-justify" aria-hidden="true"></span>
</button>
<button type="button" class="close" data-dismiss="alert" aria-label="Close" id = "closeButton" ng-show = "buttonDisplay" ng-hide = "!displayVideo" ng-click = "closeNav(); closeVideo()"><span aria-hidden="true">×</span> </button>
<div ng-show = "buttonDisplay" id = "buttonDisplayContent" class = "cssFade">
<navigate></navigate>
</div>
</summary>
<main ng-controller="ScrollCtrl">
<div id = "arrow">
<img src = "images/pointer.png" alt = "arrow" ng-click="gotoElement('panda')">
</div>
</div>
<div class = "panda" id = "panda">
<button type="button" class="btn btn-default btn-lg work"> SEE OUR WORK </button>
</div>
<main>
<div class = "experience">
<h1> Our team builds great brands and experiences. </h1>
<button type="button" class="btn btn-default btn-lg team"> MEET THE TEAM </button>
</div>
<section class = "about">
<h5> WHAT ARE WE? </h5>
<h2> Anchour is a branding agency based in Maine. </h3>
<p> We weave together creative solutions to build personal brands and experiences. We work closely with your brand to understand your needs and create solutions that produce real results. By integrating the power of identity, digital, and sensory design, we bring new life to brands everywhere.
</p>
</section>
<div class = "goodWork">
<div class = "spotlight">
<h3> Spotlight: Amanda Brill of Las Vegas </h3>
<p> Amanda Brill is a Designer at Anchour. Fueled by the purpose of helping others, she works to bring the identity of a brand to life through a creative and intensive design process. to help brands effectively communicate who they she works to bring the identity of a brand to life through a creative... </p>
<footer> Read More </footer>
</div>
<div class = "spotlight">
<h3> Spotlight: Amanda Brill of California </h3>
<p> Amanda Brill is a Designer at Anchour. Fueled by the purpose of helping others, she works to bring the identity of a brand to life through a creative and intensive design process. Her goal is to use design as a way to help brands effectively communicate who they sponsor and supporter Fueled by the purpose of.. </p>
<footer> Read More </footer>
</div>
<div class = "spotlight">
<h3> Varney Agency: Protecting What You </h3>
<p> Anchour produced Varney Agencys latest spot featuring Matt Albrecht, owner of River Drive. Working with companies from all around the world, River Drive buys, sells, reconditions and recycles reconditions and ecycles owner of used. River Drive buys, sells Varney Agencys latest spot featuring Matt Albrecht.</p>
<footer> Read More </footer>
</div>
<div class = "spotlight">
<h3> Announcing support of Not Here </h3>
<p> This week is Human Trafficking Awareness Week, so it’s great timing to share how proud we are to be a sponsor and supporter of Not Here latest spot featuring Matt Albrecht, reconditions and recycles owner of River Drive. Working with companies from all around the,a River Drive buys, sells.... </p>
<footer> Read More </footer>
</div>
</div>
<div class = "start">
<h2 id = "startWork"> Want to work with us? </h2>
<button type="button" class="btn btn-default btn-lg"> Get Started → </button>
</div>
<div id = "end">
<footer>
Home
About us
Our Team
Blog
Services
Portfolio
Contact
Sitemap
</footer>
</div>
</div>
The video is not hiding because Angular doesn't know that the model has changed. In fact, element.on() is just the plain old jQuery on function, it isn't Angular-aware.
You may have noticed that the video disappears when you click outside then inside it : that's because the ng-click handler, which gets fired first being the innermost listener, triggers the digest phase for you, causing ng-hide to update the view.
The proper way to handle this is $scope.$apply() :
var body = angular.element($document[0].body);
body.on('click',function(e) {
scope.$apply(function() {
var inElem = angular.element(e.target).inheritedData('loadVideo');
console.log(inElem);
if (inElem) {
scope.displayVideo = true;
} else {
scope.displayVideo = false;
jQuery("#playVideo").get(0).pause();
}
});
});
See this fiddle.

Categories

Resources