"use strict";
angular.module("appBanner", [])
.controller('bannerCtrl', function($scope) {
$scope.slides = ["auto", "boatowners", "commercial"];
$scope.currentIndex = 0;
$scope.setCurrentSlideIndex = function (index) {
$scope.currentIndex = index;
$scope.currentSlideIndex = $scope.slides[$scope.currentIndex];
}
$scope.isCurrentSlideIndex = function (index) {
return $scope.currentIndex === index;
};
$scope.prevSlide = function () {
$scope.currentIndex = ($scope.currentIndex > 0) ? --$scope.currentIndex : $scope.slides.length - 1;
$scope.setCurrentSlideIndex($scope.currentIndex);
};
$scope.nextSlide = function () {
$scope.currentIndex = ($scope.currentIndex < $scope.slides.length - 1) ? ++$scope.currentIndex : 0;
$scope.setCurrentSlideIndex($scope.currentIndex);
};
})
.directive('banner', function($timeout) {
return {
link: function postLink(scope, element, attrs) {
var progressBar = angular.element(".progress");
var bannerNav = angular.element(".bannerNav");
var navCircle = angular.element(".bannerNav.navCircle");
var imgSlides = angular.element(".imgSlide");
var slideTime = 1.5;
TweenMax.set(imgSlides, {
autoAlpha: 0,
display: "none"
});
TweenMax.set(progressBar, {
autoAlpha: 0
});
var tlMaster = initMasterTimeline(imgSlides, progressBar, slideTime);
scope.getWidth = function() {
return $(element).width();
};
scope.play = function(newIndexValue) {
tlMaster.play(newIndexValue);
};
scope.$watch('slideshowHover', function(newValue) {
if (newValue === true) TweenMax.to(bannerNav, 0.5, {
autoAlpha: 0.85
})
else TweenMax.to(bannerNav, 0.5, {
autoAlpha: 0.25
})
});
scope.$watch('currentSlideIndex', function(newIndexValue) {
scope.play(newIndexValue);
});
scope.$watch(scope.getWidth, function(width) {
element.css('height', width * 0.4);
});
function updateCurrentIndex(index) {
$timeout(function() {
scope.setCurrentSlideIndex(index);
});
}
function setProgress(timeline, progressBar) {
TweenMax.set(progressBar, {
scaleX: timeline.progress()
});
}
function initMasterTimeline(imgSlides, progressBar, slideTime) {
var tlAuto = initAutoTimeline(imgSlides, progressBar, slideTime);
var tlBoatowners = initBoatownersTimeline(imgSlides, progressBar, slideTime);
var tlCommercial = initCommercialTimeline(imgSlides, progressBar, slideTime);
var tlMaster = new TimelineMax({
repeat: -1
});
tlMaster.set(progressBar, {
scaleX: 0,
transformOrigin: "left"
})
.add(tlAuto, "auto")
.add(tlBoatowners, "boatowners")
.add(tlCommercial, "commercial");
return tlMaster;
}
function initAutoTimeline(imgSlides, progressBar, slideTime) {
var stayTime = 10; //for now, can make each timeline as long as you want later
var tlAuto = new TimelineLite({
onUpdate: setProgress,
onUpdateParams: ["{self}", progressBar]
});
var autoNavCircle = $(".navCircle")[0];
tlAuto.set(imgSlides[0], {
display: "block"
})
.to(progressBar, slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[0], slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[0], slideTime, {
autoAlpha: 0
}, stayTime)
.to(progressBar, slideTime, {
autoAlpha: 0
}, stayTime)
.set(imgSlides[0], {
display: "none",
onComplete: updateCurrentIndex(1)
})
return tlAuto;
}
function initBoatownersTimeline(imgSlides, progressBar, slideTime) {
var stayTime = 10; //for now, can make each timeline as long as you want later
var tlBoatowners = new TimelineLite({
onUpdate: setProgress,
onUpdateParams: ["{self}", progressBar]
});
var boatownersNavCircle = $(".navCircle")[1];
tlBoatowners.set(imgSlides[1], {
display: "block"
})
.to(progressBar, slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[1], slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[1], slideTime, {
autoAlpha: 0
}, stayTime)
.to(progressBar, slideTime, {
autoAlpha: 0
}, stayTime)
.set(imgSlides[1], {
display: "none",
onComplete: updateCurrentIndex(2)
});
return tlBoatowners;
}
function initCommercialTimeline(imgSlides, progressBar, slideTime) {
var stayTime = 10; //for now, can make each timeline as long as you want later
var tlCommercial = new TimelineLite({
onUpdate: setProgress,
onUpdateParams: ["{self}", progressBar]
});
var commercialNavCircle = $(".navCircle")[2];
tlCommercial.set(imgSlides[2], {
display: "block"
})
.to(progressBar, slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[2], slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[2], slideTime, {
autoAlpha: 0
}, stayTime)
.to(progressBar, slideTime, {
autoAlpha: 0
}, stayTime)
.set(imgSlides[2], {
display: "none",
onComplete: updateCurrentIndex(0)
});
return tlCommercial;
}
}
}
})
#slideshow{
position: relative;
}
.imgSlide{
position: absolute;
width: 100%;
}
.progress{
position: absolute;
width: 100%;
height:3px;
background: #F1F1F1;
z-index: 5;
}
.navCircleContainer {
position: absolute;
display: flex;
justify-content: space-between;
padding: 5px;
bottom: 2.5px;
left: 12.5%;
width: 75%;
height: auto;
}
.navCircle {
opacity: 0.25;
}
div.navCircle {
position: relative;
border-radius: 100%;
background:#F1F1F1;
}
.navCircle.active {
opacity:1;
}
#media only screen and (min-width: 768px) {
div.navCircle{
width: 30px;
height: 30px;
}
}
#media only screen and (max-width: 767px) {
div.navCircle{
width: 15px;
height: 15px;
}
}
.navCircle span {
position: absolute;
color:#F1F1F1;
font-weight: bold;
left: 50%;
-moz-transform: translateX(-50%);
-webkit-transform: translateX(-50%);
-ms-transform: translateX(-50%);
-o-transform: translateX(-50%);
transform: translateX(-50%);
}
#media only screen and (min-width: 768px) {
.navCircle span {
bottom: 30px;
}
}
#media only screen and (max-width: 767px) {
.navCircle span {
bottom: 20px;
}
}
.navArrow {
position: absolute;
top: 50%;
color:#F1F1F1;
-moz-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
transform: translateY(-50%);
}
#navArrowLeft {
left: 0%;
}
#navArrowRight {
right: 0%;
}
img {
width: 100%;
height: auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-animate.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/1.15.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/jquery.gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<div ng-app="appBanner" ng-controller="bannerCtrl" banner id="slideshow" ng-mouseover="slideshowHover = true" ng-mouseleave="slideshowHover = false" ng-init="slideshowHover = false">
<!-- green field with lake -->
<img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/08/l/14089545069hw66.jpg" >
<!-- waterfall -->
<img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/preview/fldr_2012_09_09/file3231347173227.jpg" >
<!-- red sunset -->
<img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/preview/fldr_2012_07_22/file541342984669.jpg" >
<div class="progress"></div>
<div id="navArrowLeft" class="navArrow bannerNav" ng-click="prevSlide()">
<div class="hidden-xs">
<i class="fa fa-angle-double-left fa-5x"></i>
</div>
<div class="hidden-sm hidden-md hidden-lg">
<i class="fa fa-angle-double-left fa-2x"></i>
</div>
</div>
<div id="navArrowRight" class="navArrow bannerNav" ng-click="nextSlide()">
<div class="hidden-xs">
<i class="fa fa-angle-double-right fa-5x"></i>
</div>
<div class="hidden-sm hidden-md hidden-lg">
<i class="fa fa-angle-double-right fa-2x"></i>
</div>
</div>
<div class="navCircleContainer">
<div class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 0" ng-mouseover="navCircleAutoHover = true" ng-mouseleave="navCircleAutoHover = false" ng-init="navCircleAutoHover = false" ng-click="play('auto')"><span class="bannerNav fade" ng-show="navCircleAutoHover === true">Lake</span></div>
<div class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 1" ng-mouseover="navCircleBoatownersHover = true" ng-mouseleave="navCircleBoatownersHover = false" ng-init="navCircleBoatownersHover = false" ng-click="play('boatowners')"><span class="bannerNav fade" ng-show="navCircleBoatownersHover === true">Waterfall</span></div>
<div class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 2" ng-mouseover="navCircleCommercialHover = true" ng-mouseleave="navCircleCommercialHover = false" ng-init="navCircleCommercialHover = false" ng-click="play('commercial')"><span class="bannerNav fade" ng-show="navCircleCommercialHover === true"> Sunset</span></div>
</div>
</div>
Working Codepen Link
I had some trouble getting this to work here in stackoverflow, but the working codepen link is provided. My problem is that the updateCurrentIndex(nextIndex) that works in conjunction with $timeout and happens onComplete at the end of each child timeline does not seem to communicate the normal increments of the index when it plays.
So, this works fine if you click next, previous, or any of the direct go to circle buttons at the bottom before the timeline has time to go to next slide (index incremented outside user control). However, when the timeline plays next slide, the index in the controller is not aware of this change and it becomes out of sync. I have been pointed towards the $timeout service as a way to fix this, but it still is not working. Any help greatly appreciated.
There is quite a bit of code to sort out in demo but you have two invalid function references like:
onComplete: updateCurrentIndex(2)
First these are hard coded values and second they will be invoked immediately not when onComplete fires as you are expecting:
To pass a function as reference you can't use () so correct way would be:
onComplete: updateCurrentIndex
But since you need to pass parameters you would need something like:
onComplete: function(arg1,arg2){ // not sure what arguments are available
var newIndex = // I'm not sure how to get index in this event
updateCurrentIndex(newIndex);
}
I just figured it out. My problem was the following: onComplete:updateCurrentIndex, onCompleteParams:[nextIndex]
I was passing it this: onComplete: updateCurrentIndex(2)
and yes it was executing immediately. it works now.
Related
I currently have a free account in SmartyStreets (aka Smarty) and need to integrate the autocomplete functionality. But after integrating the API using static values, it shows a CORS issue. Also, i have already tried the Access-Control-Allow-Origin but that also not working.
So my question is how to resolve the CORS issue?
Also, I have another question I would like to implement two other features.
autocomplete addresses and populate values in the form.
the page allows the user to type the address, send the request to SmartStreets, get the response, and display the result along with the form, empty this time, to allow the user to enter another address.
For More Details, please have a look at the below code:
Note: The Frontend code I am using is AngularJs with Typescript.
API Integration:
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import { HttpClient, HttpParams } from "#angular/common/http";
#Injectable()
export class commonservice
{
constructor(private httpclient:HttpClient){
}
getaddressauto(): Observable<any> {
let smartauth = new HttpParams().set('auth-id',"72018252-ad10-b627-1234-970404bfd187");
let smarttoken = new HttpParams().set('auth-token',"xuwSg95g4y8AObhEv3hx");
let smartsearch = new HttpParams().set('search',"Louis");
let smartcountry = new HttpParams().set('country',"FRA");
return this.httpclient.get('https://international-autocomplete.api.smartystreets.com/lookup?'+smartauth+'&'+smarttoken+'&'+smartsearch+'&'+smartcountry) ;
}
}
<html>
<head>
<title>SmartyStreets Address Verifier</title>
</head>
<body>
<div class="p-field p-col-4">
<label for="address">Address Line 1</label>
<p-autoComplete [(ngModel)]="addressautocomplete2" [suggestions]="filteredGroup" (completeMethod)="filteraddressautocomplete($event)" (onSelect)="onEndUserSelect($event)" (onClear)="onEndUserSelect(null)" field="name" [minLength]="1" formControlName="EndUserAddressLine1">
</p-autoComplete>
<div *ngFor="let addressauto of addressautocomplete">
<p>{{addressauto.name}}</p>
</div>
</div>
</body>
</html>
You shouldn't be sending your auth-id and auth-token over the web. Use your embedded key instead.
When you use your embedded key don't forget to set the referrer header.
Smarty also has a javascript sdk that could simplify a lot of this stuff
Here is a JSFiddle that may be helpful. It seems to be what you want to accomplish as far as a call to Smarty US Autocomplete Pro, followed by a call to Smarty US Street, then filling a form with a result.
https://jsfiddle.net/x8eLpgm1/1/
$(function() {
var menu = $(".us-autocomplete-pro-menu");
var input = $("#us-autocomplete-pro-address-input");
function getSuggestions(search, selected) {
$.ajax({
url: "https://us-autocomplete-pro.api.smartystreets.com/lookup?",
data: {
// Don't forget to replace the key value with your own embedded key
"key": "21102174564513388",
"search": search,
"selected": (selected ? selected : "")
},
success: function(data) {
if (data.suggestions) {
buildMenu(data.suggestions);
} else {
noSuggestions();
}
},
error: function(error) {
return error;
}
});
}
function getSingleAddressData(address) {
$.ajax({
url: "https://us-street.api.smartystreets.com/street-address?",
data: {
// Don't forget to replace the key value with your own embedded key
"key": "21102174564513388",
"street": address[0],
"city": address[1],
"state": address[2]
},
dataType: "jsonp",
success: function(data) {
$("#zip").val(data[0].components.zipcode);
$("#data-lat").html(data[0].metadata.latitude);
$("#data-lon").html(data[0].metadata.longitude);
$("#data-county").html(data[0].metadata.county_name);
$("#data-time-zone").html(data[0].metadata.time_zone);
},
error: function(error) {
return error;
}
});
}
function clearAddressData() {
$("#city").val("");
$("#state").val("");
$("#zip").val("");
$("#data-lat").empty();
$("#data-lon").empty();
$("#data-county").empty();
$("#data-time-zone").empty();
}
function noSuggestions() {
var menu = $(".us-autocomplete-pro-menu");
menu.empty();
menu.append("<li class='ui-state-disabled'><div>No Suggestions Found</div></li>");
menu.menu("refresh");
}
function buildAddress(suggestion) {
var whiteSpace = "";
if (suggestion.secondary || suggestion.entries > 1) {
if (suggestion.entries > 1) {
suggestion.secondary += " (" + suggestion.entries + " more entries)";
}
whiteSpace = " ";
}
var address = suggestion.street_line + whiteSpace + suggestion.secondary + " " + suggestion.city + ", " + suggestion.state + " " + suggestion.zipcode;
var inputAddress = $("#us-autocomplete-pro-address-input").val();
for (var i = 0; i < address.length; i++) {
var theLettersMatch = typeof inputAddress[i] == "undefined" || address[i].toLowerCase() !== inputAddress[i].toLowerCase();
if (theLettersMatch) {
address = [address.slice(0, i), "<b>", address.slice(i)].join("");
break;
}
}
return address;
}
function buildMenu(suggestions) {
var menu = $(".us-autocomplete-pro-menu");
menu.empty();
suggestions.map(function(suggestion) {
var caret = (suggestion.entries > 1 ? "<span class=\"ui-menu-icon ui-icon ui-icon-caret-1-e\"></span>" : "");
menu.append("<li><div data-address='" +
suggestion.street_line + (suggestion.secondary ? " " + suggestion.secondary : "") + ";" +
suggestion.city + ";" +
suggestion.state + "'>" +
caret +
buildAddress(suggestion) + "</b></div></li>");
});
menu.menu("refresh");
}
$(".us-autocomplete-pro-menu").menu({
select: function(event, ui) {
var text = ui.item[0].innerText;
var address = ui.item[0].childNodes[0].dataset.address.split(";");
var searchForMoreEntriesText = new RegExp(/(?:\ more\ entries\))/);
input.val(address[0]);
$("#city").val(address[1]);
$("#state").val(address[2]);
if (text.search(searchForMoreEntriesText) == "-1") {
$(".us-autocomplete-pro-menu").hide();
getSingleAddressData(address);
} else {
$("#us-autocomplete-pro-address-input").val(address[0] + " ");
var selected = text.replace(" more entries", "");
selected = selected.replace(",", "");
getSuggestions(address[0], selected);
}
}
});
$("#us-autocomplete-pro-address-input").keyup(function(event) {
if (input.val().length > 0 || input.val() === "") clearAddressData();
if (event.key === "ArrowDown") {
menu.focus();
menu.menu("focus", null, menu.menu().find(".ui-menu-item"));
} else {
var textInput = input.val();
if (textInput) {
menu.show();
getSuggestions(textInput);
} else {
menu.hide();
}
}
});
$(".us-autocomplete-pro-menu").css("width", ($("#us-autocomplete-pro-address-input").width() + 24) + "px")
});
.us-autocomplete-pro-example {
font-family: helvetica;
color: #0a0a0a;
text-align: center;
}
.us-autocomplete-pro-example .container {
background-color: #ddd;
padding: 2em;
}
.us-autocomplete-pro-example .container label {
color: #0a0a0a;
}
.us-autocomplete-pro-example .container input {
font-size: 16px;
padding: 0 .75em;
border: 1px solid #ccc;
color: #0a0a0a;
height: 3em;
box-sizing: border-box;
width: 100%;
margin-top: .5em;
}
.us-autocomplete-pro-example .container input:disabled {
background-color: #eee;
color: #999;
}
.us-autocomplete-pro-example .container .us-autocomplete-pro-input-container {
margin: 0 auto 2em;
width: 60%;
}
.us-autocomplete-pro-example .container .us-autocomplete-pro-menu {
overflow-y: scroll;
max-height: 13em;
box-shadow: 0 7px 7px rgba(0, 0, 0, 0.12);
color: #7d7d7d;
position: absolute;
text-align: left;
width: inherit;
z-index: 10;
}
.us-autocomplete-pro-example .container .us-autocomplete-pro-menu li div {
padding: .75em;
}
.us-autocomplete-pro-example .container .us-autocomplete-pro-menu b {
color: #0a0a0a;
}
.us-autocomplete-pro-example .container .us-autocomplete-pro-menu .ui-menu-item-wrapper {
padding-left: 1em;
}
.us-autocomplete-pro-example .container .labels {
display: inline-block;
font-weight: bold;
width: 40%;
}
.us-autocomplete-pro-example .container .data {
display: inline-block;
padding-left: 1em;
width: 50%;
}
.us-autocomplete-pro-example .docs-pricing-links {
font-weight: bold;
margin-top: 2em;
}
.inline {
display: inline-block;
vertical-align: top;
width: 40%;
}
.data-container {
text-align: center;
margin-bottom: 2em;
}
.align-right {
text-align: right;
}
.align-left {
text-align: left;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.js"></script>
</head>
<body>
<div class="content-white us-autocomplete-pro-example">
<h2>US Autocomplete Pro</h2>
<div class="container">
<div class="us-autocomplete-pro-input-container">
<label for="us-autocomplete-pro-address-input">Start typing a street address and watch how fast we send you
verified suggestions</label><br>
<input id="us-autocomplete-pro-address-input" placeholder="Enter Address" autocomplete="smartystreets"/>
<ul class="us-autocomplete-pro-menu" style="display:none;"></ul>
<div class="disabled-inputs">
<input id="city" placeholder="City" disabled />
<div class="state-and-zip">
<input id="state" placeholder="State" disabled />
<input id="zip" placeholder="Zip*" disabled />
</div>
</div>
</div>
<div class="data-container">
<div>
<h3>*Additional Data</h3>
<div class="labels inline align-right">
<span>Latitude:</span><br>
<span>Longitude:</span><br>
<span>County:</span><br>
<span>Time Zone:</span>
</div>
<div class="data inline align-left">
<span id="data-lat"></span><br>
<span id="data-lon"></span><br>
<span id="data-county"></span><br>
<span id="data-time-zone"></span>
</div>
<div class="more-data">
... along with 32 other points of data.
</div>
</div>
</div>
<div class="disclaimer">*ZIP Code & Additional Data retrieved from <a href="https://smartystreets.com/products/apis/us-street-api">US
Street Address API</a></div>
</div>
<div class="docs-pricing-links">
Pretty cool huh? You should see the <a href="https://smartystreets.com/docs/cloud/us-autocomplete-api#autocomplete-professional">Autocomplete
Pro Docs</a> for more info
</div>
</div>
</body>
</html>
I just studied React from YouTube lessons, and there all the lessons were built on classes and the usual this.setState, without hooks. How would this React code look without React-hooks and with class components rather than functional components?
The code itself implements an image slider:
React:
function Slider({ items }) {
const [ active, setActive ] = React.useState(0);
const { length, [active]: slide } = items;
const next = e => setActive((active + +e.target.dataset.step + length) % length);
const goTo = e => setActive(+e.target.dataset.index);
React.useEffect(() => {
const timeout = setTimeout(() => setActive((active + 1 + length) % length), 5000);
return () => clearTimeout(timeout);
}, [active, length]);
return (
<div>
<div className="slideshow-container">
<div className="mySlides fade">
<div className="numbertext">{active + 1} / {length}</div>
<img src={slide.img} />
<div className="text">{slide.title}</div>
</div>
<a className="prev" onClick={next} data-step={-1}>❮</a>
<a className="next" onClick={next} data-step={+1}>❯</a>
</div>
<div className="dots">
{items.map((n, i) => (
<span
key={n.id}
className={`dot ${i === active ? 'active' : ''}`}
onClick={goTo}
data-index={i}
></span>
))}
</div>
</div>
);
}
const items = [
{ title: 'One', img: 'https://upload.wikimedia.org/wikipedia/commons/1/1f/Purity_of_nature.jpg' },
{ title: 'Two', img: 'https://mairie-balma.fr/wp-content/uploads/2016/06/Lhers.jpg' },
{ title: 'Three', img: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRt-b1iBqHQ_emkm1wFmkM7KQskzIqg7YQPZWW85Sa7k2nNLwgjMw' },
].map((n, i) => ({ ...n, id: i + 1 }));
ReactDOM.render(<Slider items={items} />, document.getElementById('app'));
HTML
<div id="app"></div>
CSS:
.slideshow-container {
max-width: 500px;
position: relative;
margin: auto;
}
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
.text {
color: #f2f2f2;
font-size: 15px;
padding: 8px 12px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
box-sizing: border-box;
}
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
.dots {
display: flex;
justify-content: center;
}
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
.mySlides img {
width: 100%;
}
Something like this (not fully tested):
class Slider {
constructor(props) {
super(props);
this.state = {
active: 0
}
}
let timeout = null;
componentDidMount() {
this.timeout = setTimeout(() => this.setActive(), 5000);
}
componentDidUpdate(prevProps) {
const { active } = this.props;
if (prevProps.active !=== active {
if (this.timeout) {
clearTimeout(this.timeout);
}
this.timeout = setTimeout(() => this.setActive(), 5000);
});
}
componentDidUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
const setActive = (newActive) => {
const { length } = items;
this.setState({
active: (newActive + 1 + length) % length
});
}
const next = e => {
const { length } = items;
this.setActive((this.state.active + +e.target.dataset.step + length) % length);
}
const goTo = e => this.setActive(+e.target.dataset.index);
render() {
const { length } = items;
const {active} = this.state;
return (
<div>
<div className="slideshow-container">
<div className="mySlides fade">
<div className="numbertext">{active + 1} / {length}</div>
<img src={slide.img} />
<div className="text">{slide.title}</div>
</div>
<a className="prev" onClick={this.next} data-step={-1}>❮</a>
<a className="next" onClick={this.next} data-step={+1}>❯</a>
</div>
<div className="dots">
{items.map((n, i) => (
<span
key={n.id}
className={`dot ${i === active ? 'active' : ''}`}
onClick={this.goTo}
data-index={i}
></span>
))}
</div>
</div>
);
}
}
const items = [
{ title: 'One', img: 'https://upload.wikimedia.org/wikipedia/commons/1/1f/Purity_of_nature.jpg' },
{ title: 'Two', img: 'https://mairie-balma.fr/wp-content/uploads/2016/06/Lhers.jpg' },
{ title: 'Three', img: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRt-b1iBqHQ_emkm1wFmkM7KQskzIqg7YQPZWW85Sa7k2nNLwgjMw' },
].map((n, i) => ({ ...n, id: i + 1 }));
ReactDOM.render(<Slider items={items} />, document.getElementById('app'));
In this plunk I have a div that needs to be drawn dragging the mouse. I'm using mouse up/move/down events. The problem that I have is that the div "flickers" when I drag down. How to fix this?
HTML
<style>
.frame {
width: 300px;
height: 300px;
background-color: orange;
position: relative;
}
.sel{
border:2px solid black;
background-color: #ffffff;
position:absolute;
}
</style>
<div class="frame" ng-mousedown="mouseDown($event)"
ng-mousemove="mouseMove($event)"
ng-mouseup="mouseUp()">
<div class="sel" ng-show="show"
ng-style="{top:selTop+'px', left:selLeft+'px', width:selWidth+'px', height:selHeight+'px'}"></div>
</div>
Javascript:
var app = angular.module('app', []);
app.controller('ctl', function ($scope) {
$scope.startPoint = {};
$scope.show = false;
$scope.mouseDown = function(event) {
$scope.startPoint = { x: event.offsetX, y: event.offsetY };
$scope.show = true;
};
$scope.mouseMove = function(event) {
if (!$scope.startPoint.x)
return;
$scope.selTop = $scope.startPoint.y;
$scope.selLeft = $scope.startPoint.x;
$scope.selHeight = event.offsetY - $scope.startPoint.y;
$scope.selWidth = event.offsetX - $scope.startPoint.x;
};
$scope.mouseUp = function() {
$scope.startPoint = {};
$scope.show = false;
};
});
just add these css properties
border: none;
color: transparent;
text-shadow: 0 0 0 gray;
text-align: center;
&:focus {
outline: none;
}
see the plunker http://embed.plnkr.co/9WntGyBLQxYSxkFjDAy2/
I have problem with adding search by address option to my angular google maps code...
http://jsfiddle.net/lukasz9999/bmp62fan/
var mapOptions = {
zoom: 14,
center: new google.maps.LatLng(30.0000, -98.0000),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
I suppose that I have to add a geocoder somehow but I don't know how.
If someone has a working example of Angular Google Map set position by address it would be great
Thank You
I would suggest to utilize Autocomplete feature for that purpose, below is provided the modified example:
Note: since Autocomplete is a feature of the Places library, be sure
to include it, e.g. libraries=places
angular.module('mapsApp', [])
.controller('MapCtrl', function ($scope) {
var mapOptions = {
zoom: 10,
center: new google.maps.LatLng(-33.8688, 151.2195),
mapTypeId: google.maps.MapTypeId.TERRAIN
}
$scope.map = new google.maps.Map(document.getElementById('map'), mapOptions);
$scope.markers = [];
var infoWindow = new google.maps.InfoWindow();
//init autocomplete
var input = document.getElementById('pac-input');
$scope.map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
var autocomplete = new google.maps.places.Autocomplete(input);
//autocomplete.bindTo('bounds', $scope.map);
autocomplete.addListener('place_changed', function () {
setPlace();
});
var setPlace = function () {
//infoWindow.close();
var place = autocomplete.getPlace();
if (!place.geometry) {
window.alert("Autocomplete's returned place contains no geometry");
return;
}
// If the place has a geometry, then present it on a map.
if (place.geometry.viewport) {
$scope.map.fitBounds(place.geometry.viewport);
} else {
$scope.map.setCenter(place.geometry.location);
}
createMarker({ lat: place.geometry.location.lat(), lng: place.geometry.location.lng(), address: place.formatted_address });
}
var createMarker = function (info) {
var marker = new google.maps.Marker({
map: $scope.map,
position: new google.maps.LatLng(info.lat, info.lng),
title: info.address
});
marker.content = '<div class="infoWindowContent">' + info.address + '</div>';
google.maps.event.addListener(marker, 'click', function () {
infoWindow.setContent('<h2>' + marker.title + '</h2>' + marker.content);
infoWindow.open($scope.map, marker);
});
$scope.markers.push(marker);
}
$scope.openInfoWindow = function (e, selectedMarker) {
e.preventDefault();
google.maps.event.trigger(selectedMarker, 'click');
}
});
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 600px;
}
.controls {
margin-top: 10px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 300px;
}
#pac-input:focus {
border-color: #4d90fe;
}
.pac-container {
font-family: Roboto;
}
<script src="http://code.angularjs.org/1.2.10/angular.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<div ng-app="mapsApp" ng-controller="MapCtrl">
<input id="pac-input" class="controls" type="text" placeholder="Enter a location">
<div id="map"></div>
</div>
JSFiddle
If you go to the https://material.angularjs.org website,
you will notice a very nice Accordion dropdown menu in the sidenav.
I'm trying to find a simplified version of this feature.
I've looked into many examples it appears many of them are no longer working.
I don't need it complicated. So no need of repetative items. I can do all that. I need the basic functionality.
From what I've researched they have an expando feature being developed, but until then is there a work around?
Updated:
I wasn't able to find a good angular material design, but I was able to find an angular method.
https://github.com/sherwaniusman/angular-accordion
The following fiddle really helped me:
Accordion example
I have also added functionality which allows expanding only 1 menu at a time, if others opened, it will automatically close them.
Code in Controller:
function controller($scope) {
$scope.accordianData = [
{ "heading" : "About Us", "content" : "" },
{ "heading" : "Terms of Use", "content" : "" },
{ "heading" : "Privacy Policy", "content" : "" },
{ "heading" : "Help", "content" : "" },
];
);
// To expand or collapse the current view
//This functionality automatically closes the other expanded lists
$scope.toggleView = function(ary, data, index){
for(var i=0; i<ary.length; i++){
if(i!=index) { ary[i].expanded=false; }
else { data.expanded=!data.expanded; }
}
}
}
And the view/html Code is:
Just tweaked a bit of functionality as per my requirements:
<md-content id="dynamic-content" class="f-clear-padding">
<div class="md-accordion" ng-repeat="data in accordianData">
<!-- <md-toolbar ng-init="data.expanded = false" ng-click="data.expanded = !data.expanded"> this was the code in demo-->
<md-toolbar ng-init="data.expanded = false" ng-click="toggleView(accordianData, data, $index)">
<div class="md-toolbar-tools">
<!-- <h2> -->
<div ng-bind="data.heading"></div>
<!-- </h2> -->
<div flex=""></div>
<div ng-class="{expandCollapse:true, active:data.expanded}"></div>
</div>
</md-toolbar>
<div style="overflow:scroll" ng-class="{dataContent:true, activeContent:data.expanded}">
<div style="padding:10px" ng-bind-html="data.content"></div>
</div>
<div>
</md-content>
And the css part:
.md-accordion .expandCollapse { width:30px; height:30px; position:relative; font-size:20px; font-weight:bold; cursor:pointer; color:#fff; display:block; margin-top: -2px; margin-left: -2px; overflow:hidden; }
.md-accordion .expandCollapse:active { border:0px; }
.md-accordion .expandCollapse:before, .md-accordion .expandCollapse:after { width:30px; height:30px; display:block; position:absolute; top:0; left:0; line-height:32px; text-align:center; -webkit-transition: .3s all ease-out; transition: .3s all ease-out; }
.md-accordion .expandCollapse:before { opacity:1 -webkit-transform: rotate(0deg); transform: rotate(0deg); content: "|"; margin-top:-3px; }
.md-accordion .expandCollapse:after { opacity:1; -webkit-transform: rotate(-90deg); transform: rotate(-90deg); content: "|"; margin-left:-3px; }
.md-accordion .active:before { opacity:1; -webkit-transform: rotate(90deg); transform: rotate(90deg); margin-left:3px; margin-top:0px; }
.md-accordion .dataContent { background: #F2F2F2; height:0px; overflow:hidden; -webkit-transition: .3s all ease-out; transition: .3s all ease-out; }
.md-accordion .activeContent { height:60vh; padding:0; display:block; }
.md-accordion md-toolbar{ cursor:pointer; border-bottom:1px solid rgb(63,107,181) }
Here we have fixed the height of the expandable list in order to keep the list items still visible, else once you expand a div having a huge content the user may feel that it's the only list item available and may not be able to see the other items if any of the div is expanded, the overflow:scroll allows the view to be scroll through, else it will be stiff and the user won't be ablt to view the entire content.
Hope this is helpful... :)
So this is what I ended up using
Directive HTML Code
need a right and down arrow img
<ang-accordion one-at-a-time="true" icon-position="right" close-icon-url="<?php echo URL; ?>/img/icons/right-icon.png" open-icon-url="<?php echo URL; ?>/img/icons/down-icon.png">
<collapsible-item ng-repeat="item in items" item-title="" initially-open="">
<div>Text</div>
</collapsible-item>
</ang-accordion>
Script to include
<script type="text/javascript" src="<?php echo URL; ?>/js/angular/controllers/accordion.js"></script>
JS: accordion.js
app.controller('angAccordionController', ['$scope', function($scope){
var collapsibleItems = [];
this.openCollapsibleItem = function(collapsibleItemToOpen) {
if( $scope.oneAtATime ) {
angular.forEach(collapsibleItems, function(collapsibleItem) {
collapsibleItem.isOpenned = false;
collapsibleItem.icon = collapsibleItem.closeIcon;
});
}
collapsibleItemToOpen.isOpenned = true;
};
this.addCollapsibleItem = function(collapsibleItem) {
collapsibleItems.push(collapsibleItem);
if ( $scope.closeIconClass !== undefined || $scope.openIconClass !== undefined ) {
collapsibleItem.iconsType = 'class';
collapsibleItem.closeIcon = $scope.closeIconClass;
collapsibleItem.openIcon = $scope.openIconClass;
}
else if ( $scope.closeIconUrl !== undefined || $scope.openIconUrl !== undefined ) {
collapsibleItem.iconsType = 'url';
collapsibleItem.closeIcon = $scope.closeIconUrl;
collapsibleItem.openIcon = $scope.openIconUrl;
}
collapsibleItem.iconIsOnLeft = $scope.iconPosition == 'left' ? true: false;
};
}])
.directive('angAccordion', function() {
return {
restrict: 'EA',
transclude: true,
replace: true,
scope: {
oneAtATime: '#',
closeIconUrl: '#',
openIconUrl: '#',
closeIconClass: '#',
openIconClass: '#',
iconPosition: '#'
},
controller: 'angAccordionController',
template: '<div class="accordion" ng-transclude></div>'
};
});
angular.module('collapsibleItem', []).directive('collapsibleItem', function() {
return {
require: '^angAccordion',
restrict: 'EA',
transclude: true,
replace: true,
scope: {
itemTitle: '#',
itemDisabled: '=',
initiallyOpen: '#'
},
link: function(scope, element, attrs, accordionController) {
scope.isOpenned = (scope.initiallyOpen == "true") ? true : false;
accordionController.addCollapsibleItem(scope);
if(scope.isOpenned)
scope.icon = scope.openIcon;
else
scope.icon = scope.closeIcon;
scope.toggleCollapsibleItem = function () {
if(scope.itemDisabled)
return;
if(!scope.isOpenned) {
accordionController.openCollapsibleItem(this);
scope.icon = scope.openIcon;
}
else {
scope.isOpenned = false;
scope.icon = scope.closeIcon;
}
};
scope.getIconUrl = function ( type ) {
return type == 'url' ? scope.icon : null;
};
},
template: '<div class="collapsible-item" ng-class="{open: isOpenned}"><div class="title" ng-class="{disabled: itemDisabled}" ng-click="toggleCollapsibleItem()">{{itemTitle | limitTo:28 }}<i ng-show="iconsType == \'class\'" class="{{icon}} icon" ng-class="{iconleft: iconIsOnLeft}"></i><img ng-show="iconsType == \'url\'" class="icon" ng-class="{iconleft: iconIsOnLeft}" ng-src="{{getIconUrl(iconsType)}}" /></div><div class="body"><div class="content" ng-transclude></div></div></div>'
};
});
CSS
.collapsible-item {
margin-bottom: 0px;
}
.collapsible-item .title {
padding: 10px;
background-color: #dfdfdf;
border: 0px solid #ccc;
cursor: pointer;
}
.collapsible-item .title .icon {
float: right;
height: 20px;
width: 20px;
font-size: 19px !important;
padding-right: 1px;
}
.collapsible-item .title .iconleft {
float: left !important;
}
.collapsible-item .title.disabled {
background: #eee;
color: #999;
cursor: text;
}
.collapsible-item .body {
position: relative;
top: -4px;
max-height: 0;
overflow: hidden;
border: 1px solid #ccc;
border-top: 0;
z-index: -1;
-webkit-transition: max-height 0.5s ease;
-moz-transition: max-height 0.5s ease;
-o-transition: max-height 0.5s ease;
transition: max-height 0.5s ease;
}
.collapsible-item .body .content {
padding: 5px 15px 5px 15px;
}
.collapsible-item.open .body {
max-height: 1000px;
z-index: 1;
}