Im attempting to implement the following Flexbox table from Vasan Subramanian with vue.
That table is built manually, but That doesnt give much help when trying to make a component of it.
So Im willing to make it dinamically. and my first obstacle is to group each pair of two rows inside one div. Like the following
<div class="Table">
<div class="Table-row Table-header">
<div class="Table-row-item" v-for="key in cols" v-bind:style="{'flex-basis':basis, 'flex-grow':key.grow}">
<a #click="sortBy(key)">{{key.title}} <i v-if="key.sortField==sort" class="{{reverse==1?'fa fa-sort-desc':'fa fa-sort-asc'}}" aria-hidden="true"></i></a>
</div>
</div>
The previous code gives the normal table header
<div class="Table-row-item">
firstname
</div>
<div class="Table-row-item">
lastname
</div>
<div class="Table-row-item">
email
</div>
<div class="Table-row-item">
company
</div>
Im trying to achieve the following:
<div class=divider>
<div class="Table-row-item">
firstname
</div>
<div class="Table-row-item">
lastname
</div>
</div>
<div class=divider>
<div class="Table-row-item">
email
</div>
<div class="Table-row-item">
company
</div>
</div>
My Issue is I dont know how to represent that in code.
Any help would be very appreciated. I couldnt find any good examples about responsive tables with Flexbox. just the previous and this other from Jonathan Lehman An excellent Lecture using Sass.
You want to group your columns, and then loop over the columns within each group. Use a computed to do the grouping. Your grow specification doesn't quite fit this model; it seems like you want to have one grow spec per group, but I don't know exactly what the goal is there.
This code makes column groups of whatever size you choose and puts them in your dividers.
new Vue({
el: '.Table',
data: {
columns: ['firstname', 'lastname', 'email', 'company'].map((n) => ({
title: n,
sortField: n
})),
perDivider: 2,
basis: '50%',
grow: 1,
sort: null
},
computed: {
colGroups: function() {
return this.by(this.perDivider, this.columns);
}
},
methods: {
by: function(n, arr) {
const result = [];
for (var i = 0; i < arr.length; i += n) {
result.push(arr.slice(i, i + n));
}
return result;
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<div class="Table">
Table here
<div class="Table-row Table-header">
<div class="Table-row-item" v-for="colGroup in colGroups" v-bind:style="{'flex-basis':basis, 'flex-grow':grow}">
<a v-for="key in colGroup" #click="sortBy(key)">
{{key.title}} <i v-if="key.sortField==sort" class="{{reverse==1?'fa fa-sort-desc':'fa fa-sort-asc'}}" aria-hidden="true"></i>
</a>
</div>
</div>
</div>
I Started with a computed property
odd(){
var numberOdds = 0;
var arr = [];
for (var i = 0; i < this.cols.length; i++) {
if (i % 2 == 0) {
numberOdds++;
}
}
var j=0;
for (i=0;i<numberOdds;i++){
this.arr[i]=j;
j+=2;
}
return numberOdds;
}
so..
<div class="Table">
<div class="Table-row Table-header">
<div class="divider" v-for="number in odd">
{{cols[arr[number]].title}}
{{cols[arr[number]+1].title}}
</div>
</div>
<div class="Table-row" v-for="item in items.data" >
<div class="divider" v-for="number in odd">
<div class="Table-row-item">
{{item[cols[arr[number]].name]}}
</div>
<div class="Table-row-item">
{{item[cols[arr[number]+1].name]}}
</div>
</div>
</div>
</div>
This works. testing purposes
Related
I have tried :nth-of-type and :nth-child, but those don't work for selecting a specific instance on the entire page. For example, if I wanted to select the 8th div.box element below ("plane") how can I do this?
<div>
<div class="box">blueberry</div>
<div class="box">cherry</div>
<div class="box">pineapple</div>
<div class="box">orange</div>
<div class="box">grape</div>
</div>
<div>
<div class="box">car</div>
<div class="box">boat</div>
<div class="box">plane</div>
<div class="box">bike</div>
<div class="box">motorcycle</div>
</div>
You can do this with javascript. I don't think you can do such a specific task with CSS, but I'm not sure.
let base = document.getElementsByTagName("div");
let divs = [];
for (let i = 0; i < base.length; i++) {
let elems = base[i].getElementsByTagName("div");
for (let j = 0; j < elems.length; j++) {
divs.push(elems[j])
}
}
function findNElement(n) {
return divs[n-1].textContent; // This is to return text. Remove .textContent to remove th element
}
console.log(findNElement(8));
<div>
<div class="box">blueberry</div>
<div class="box">cherry</div>
<div class="box">pineapple</div>
<div class="box">orange</div>
<div class="box">grape</div>
</div>
<div>
<div class="box">car</div>
<div class="box">boat</div>
<div class="box">plane</div>
<div class="box">bike</div>
<div class="box">motorcycle</div>
</div>
You can use this snippet to select a certain element of the textContent of the element.
For the completely general case, where you do not know the document's structure (i.e. div.box elements are 'scattered' as you say) I think you'll need Javascript.
The element you want is
document.querySelectorAll('div.box')[7]
of course you'll want to check that it actually exists before trying to do anything with it so something like:
function findBox(n) { //n starts at 1
const boxes = document.querySelectorAll('div.box');
if (boxes.length >= n) return boxes[n-1];
else return false;
}
let n = 8;
let box = findBox(n);
if (box) {
box.style.backgroundColor = 'silver';
}
else {
console.log('There is no ' + n + 'div.box');
}
<div>
<div class="box">blueberry</div>
<div class="box">cherry</div>
<div class="box">pineapple</div>
<div class="box">orange</div>
<div class="box">grape</div>
</div>
<div>
<div class="box">car</div>
<div class="box">boat</div>
<div class="box">plane</div>
<div class="box">bike</div>
<div class="box">motorcycle</div>
</div>
I am making a request to a personal API that returns the url of about 300 images (approximately) and all these images I must show them in a Carousel.
The problem is that my page lasts a long time to load because when the surcharge begins to load the 300 images. the carousel shows 6 images per pass, and what I want is for you to load the images as you click on the "NEXT" or "PREV" button to make the page load faster. That would be the right way to do it, right?
I'm starting with angular and it's the first time I make an application of this type. Somebody could help me? I have researched but I have not found much information that helps me or I do not know the terminology of what I need to use in this case.
This is the code of the carousel where I show the images that I comment, I am using NGX-BOOTSTRAP:
<div class="container" >
<div class="d-flex justify-content-center align-items-center">
<div class="d-flex align-items-center justify-content-center">
<div> <span class="text-hot">
<b>HOT</b> </span> </div>
</div>
<div id="div-redondo" class="d-flex ml-2 align-items-center justify-content-center">
<div class="text-hot align-middle">
list
</div>
</div>
</div>
</div>
<!-- Imagen de Pre-Carga-->
<div class="container-fluid d-flex justify-content-center" id="cont-preCarga" *ngIf="preCarga">
<img src="../../assets/images/slider/spinner.gif">
</div>
<app-modal [inmueble]="this.inmueble2" class="modal fade" id="exampleModal2" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> </app-modal>
<carousel [itemsPerSlide]="itemsPerSlide"
[singleSlideOffset]="singleSlideOffset"
[interval]="false"
[noWrap]="noWrap">
<slide class="col-md-2" *ngFor="let imagenPortada of this.hostlistService.inmuebles; let index=index" style="width: 500px;">
<img src="{{url}}{{imagenPortada.id}}_{{imagenPortada.fotos[0]}}" alt="imagen de slide" style="display: block; width: 100%; height: 300px;"> <!-- <-----HERE IS WHERE I AM SHOWING THE IMAGES -->
<!--<img src="../../assets/images/slider/logo.png" alt="imagen de slide" style="z-index: 10; width: 100%; height: 300px; position: absolute; left: 0; top:0;">-->
<!-- <div class="carousel-caption">
<h4>Slide {{index}}</h4>
</div> -->
<div class="row">
<div class="col-12">
<p class="text-left text-precio"> <i class="fas fa-dollar-sign">
</i> Precio: {{imagenPortada.precio | currency: 'USD':true:'1.2-2'}}
</p>
</div>
</div>
<div class="row">
<div class="col-12">
<p class="text-left"> <i class="fas fa-map-marker-alt"></i> Ubicacion: {{imagenPortada.precio | currency: 'USD':true:'1.2-2'}}
</p>
</div>
</div>
<div class="row">
<div class="d-flex col-12">
<div class="cont-verDetalles d-flex justify-content-center">
<button (click)="obtenerInfo(imagenPortada)" type="button" class="mt-2 btn btn-secondary" data-toggle="modal" data-target="#exampleModal2">Ver detalles</button>
</div>
</div>
</div>
</slide>
</carousel>
This is an image of the carousel, where I only show 6 images, when I click on the "NEXT" or "PREV" button they run one by one to show the following:
And here you can see what I want to avoid, that they are loading the pile of images that I do not need to show until I need them in the carousel since they are too many:
How could I do to avoid that?
I would be very grateful to the person who can help me with this. Thanks in advance.
This is a good question. To start off, we'll have 2 arrays
a masterArray which has all the URLs of the images;
an imagesArray which will be array linked to the carousel, it will have only 1 image to start of with... which means that when the page loads, we had loaded only one image.
we simply add a url from the masterArray into the imagesArray on each slide change event [name of the event is: activeSlideChange];
relevant HTML (single slide carousel):
<carousel (activeSlideChange)='gotChange()'>
<slide *ngFor="let img of imagesArray; let idx of index" >
<img src="{{img}}" alt="slide {{idx}}" style="display: block; width: 100%;">
</slide>
</carousel>
relevant TS (single slide carousel):
import { Component, ViewChild } from '#angular/core';
import { CarouselComponent } from 'ngx-bootstrap';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
#ViewChild(CarouselComponent) myCarousel: CarouselComponent;
name = 'Angular';
masterArray = ['https://valor-software.com/ngx-bootstrap/assets/images/nature/1.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/2.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/3.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/4.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/5.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/6.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/7.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/8.jpg',
];
imagesArray = ['https://valor-software.com/ngx-bootstrap/assets/images/nature/1.jpg'];
loopcomplete: boolean = false;
constructor() { }
gotChange() {
console.log('got change', this.myCarousel.activeSlide);
if (!this.loopcomplete) {
if (this.myCarousel.activeSlide + 1 < this.masterArray.length) {
this.imagesArray.push(this.masterArray[this.myCarousel.activeSlide + 1]);
} else { this.loopcomplete = true; }
}
}
}
complete working stackblitz here
the image to show the lazy loading of images
UPDATE: in light of questioner's comment below... the event that we're looking for is slideRangeChange
relevant HTML (multi slide carousel):
<carousel [itemsPerSlide]="itemsPerSlide"
[singleSlideOffset]="singleSlideOffset"
[noWrap]="noWrap"
(activeSlideChange)='gotChange()'
(slideRangeChange)='gotRangeChange()'
[showIndicators]='false'
[interval]='false'
>
<slide *ngFor="let img of imagesArray; let idx of index" >
<img [src]="img" alt="slide {{idx}}" style="display: block; width: 100%;">
</slide>
</carousel>
relevant TS (multi slide carousel):
import { Component, ViewChild } from '#angular/core';
import { CarouselComponent } from 'ngx-bootstrap';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
#ViewChild(CarouselComponent) myCarousel: CarouselComponent;
name = 'Angular';
masterArray = ['https://valor-software.com/ngx-bootstrap/assets/images/nature/1.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/2.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/3.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/4.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/5.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/6.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/7.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/8.jpg',
];
imagesArray = ['https://valor-software.com/ngx-bootstrap/assets/images/nature/1.jpg',
'https://valor-software.com/ngx-bootstrap/assets/images/nature/2.jpg',
];
loopcomplete: boolean = false;
itemsPerSlide = 2;
singleSlideOffset = true;
noWrap = true;
activeRange = 0;
constructor() { }
gotRangeChange() {
if (!this.loopcomplete) {
if (this.activeRange + 2 < this.masterArray.length) {
this.activeRange = this.activeRange + 2;
this.imagesArray = this.imagesArray.concat(this.masterArray[this.activeRange]);
this.imagesArray = this.imagesArray.concat(this.masterArray[this.activeRange + 1]);
} else {
this.loopcomplete = true;
}
}
}
}
complete working stackblitz (multi slide carousel)
<ion-slide ng-repeat="category in uniqueCategories" ng-if="$index % 4 === 0">
<div class="row" id="rowInSlider">
<div class="col col-25" ng-if="$index < uniqueCategories.length" ng-click="CategorySelected(uniqueCategories[$index], $index)">
<span class="img-centered img-padding imageDiv button button-icon">
<img class="smaller" src="img/south-indian-category-thumb.png">
</span>
<p class="smaller">{{uniqueCategories[$index]}}</p>
</div>
<div class="col col-25" ng-if="$index+1 < uniqueCategories.length" ng-click="CategorySelected(uniqueCategories[$index+1])">
<div class="img-centered img-padding imageDiv button button-icon">
<img class="smaller" src="img/south-indian-category-thumb.png">
</div>
<p class="smaller">{{uniqueCategories[$index+1]}}</p>
</div>
</ion-slide>
How can I set the background color for selected div?
This is what I tried:
<div class="col col-25" ng-if="$index < uniqueCategories.length" ng-click="CategorySelected(uniqueCategories[$index], $index)" ng-class="{selectedCategory: selectedCategory[$index]" >
controller:
$scope.CategorySelected=function(categoryName, indexNumber){
console.log(indexNumber)
$rootScope.readyToRender=false;
var selectedCategory={}
selectedCategory[indexNumber]=true;
}
But it does not work and I get no background color.
You wrote:
ng-class="{selectedCategory: selectedCategory[$index]"
First, there is a missing curly bracket, but there is also another problem: you have to expose selectedCategory on the $scope:
$scope.CategorySelected = function (indexNumber){
$scope.selectedCategory = {};
$scope.selectedCategory[indexNumber] = true;
}
Then:
ng-class="{selectedCategory: selectedCategory[$index]}"
That said, what you want to achieve here is probably better done by adding a flag isSelected to the category object.
I am creating an audio player of sorts and i have run into a brick wall. I have added a progress bar that updates according to the song being played.
However, I want the progress bar to be clickable and to jump to the time of the track when its clicked (like every regular player).
<div class="music-stream-wrapper">
<ul class="music-stream">
<li>
<div class="player-wrapper">
<div class="album-art">
<img src="https://i1.sndcdn.com/artworks-000108593302-0ek7n6-t120x120.jpg" alt="" />
</div>
<div class="meta-controls">
<div class="play-controls">
<!-- Content -->
<div class="track">
<h4 class="title">Tail toddle - Unknown</h4>
<span class="author">john.doe</span>
<span class="uploaded">a few seconds ago</span>
</div>
<div class="spectrum">
<div class="play-pause-button">
</div>
<div class="spectrum-wrapper">
<div id="spectrum_11"></div>
<div class="progress">
<progress value="0" max="1"></progress>
</div>
</div>
</div>
</div>
<div class="intent">
<ul class="buttons">
<li>Like</li>
<li>Download</li>
<li>Share</li>
</ul>
<ul class="meta">
<li><span class="liked">♥ 13</span></li>
<li><span class="played">► 123</span></li>
<li><span>♥ 3</span></li>
</ul>
</div>
</div>
</div>
</li>
</ul>
</div>
<audio src="http://tonycuffe.com/mp3/tailtoddle_lo.mp3" id="mockSong"></audio>
I have created a mock player in CodePen heres the url: View in CodePen
I ended up using a jQuery UI slider and updating it dynamically as the track position changed.
It will help you. try to evaluate what you desire for
http://jsfiddle.net/ryanhagz/8u76B/20/
HTML
<div id="progress"></div>
<div id="back">back</div>
<div id="cont">cont</div>
JAVASCRIPT
//PROGRESS BAR
$("#progress").progressbar({
value: 0
});
//UPDATING PROGRESS BAR WHEN CONTINUE BUTTON CLICKED
var currValue = 0,
toValue = 0;
$("#cont").button().click(function () {
currValue = $("#progress").progressbar("value");
if (currValue + 25 <= 100) {
toValue = currValue + 25;
animateProgress();
}
});
//DECREASING PROGRESS BAR WHEN GO BACK BUTTON CLICKED
$("#back").button().click(function () {
currValue = $("#progress").progressbar("value");
if (currValue - 25 >= 0) {
toValue = currValue - 25;
animateProgress();
}
});
function animateProgress() {
if (currValue < toValue) {
$("#progress").progressbar("value", currValue + 1);
currValue = $("#progress").progressbar("value");
setTimeout(animateProgress, 4);
} else if (currValue > toValue) {
$("#progress").progressbar("value", currValue - 1);
currValue = $("#progress").progressbar("value");
setTimeout(animateProgress, 4);
}
}
So I am attempting to create a menu element that shows and hides specific divs on a page, while also changing the text of the menu. After a little searching I have it worked out for the most part (although I know the code is a bit kludgey):
$(document).ready(function(){
$('.section[id="option1"]').click(function(){
$(this).text($(this).text() == 'OPTION1' ? 'OPTION1 >>' : 'OPTION1');
$('.blurb').not('.blurb[id="option1"]').hide();
$('.blurb[id="option1"]').slideToggle();
});
$('.section[id="option2"]').click(function(){
$(this).text($(this).text() == 'OPTION2' ? 'OPTION2 >>' : 'OPTION2');
$('.blurb').not('.blurb[id="option2"]').hide();
$('.blurb[id="option2"]').slideToggle();
});
$('.section[id="option3"]').click(function(){
$(this).text($(this).text() == 'OPTION3' ? 'OPTION3 >>' : 'OPTION3');
$('.blurb').not('.blurb[id="option3"]').hide();
$('.blurb[id="option3"]').slideToggle();
});
$('.section[id="option4"]').click(function(){
$(this).text($(this).text() == 'OPTION4' ? 'OPTION4 >>' : 'OPTION4');
$('.blurb').not('.blurb[id="option4"]').hide();
$('.blurb[id="option4"]').slideToggle();
});
$('.section[id="option5"]').click(function(){
$(this).text($(this).text() == 'OPTION5' ? 'OPTION5 >>' : 'OPTION5');
$('.blurb').not('.blurb[id="option5"]').hide();
$('.blurb[id="option5"]').slideToggle();
});
$('.section[id="option6"]').click(function(){
$(this).text($(this).text() == 'OPTION6' ? 'OPTION6 >>' : 'OPTION6');
$('.blurb').not('.blurb[id="option6"]').hide();
$('.blurb[id="option6"]').slideToggle();
});
});
(full code in action can be viewed here)
This code works for the most part, except that if you already have a certain element (class="blurb") shown, when you click on the menu item (class="section") for another element, the menu indicates that the other element is still open. It seems like there must be a simple way to append or remove the desired text on click, but I can't seem to find a good way of doing it. Would it be worth rewriting the code using something like expander.js?
Here is the effected html
<div class="nav">
<div class="section" id="option1">option1</div>
<div class="section" id="option2">option2</div>
<div class="section" id="option3">option3</div>
<div class="section" id="option4">option4</div>
<div class="section" id="option5">option5</div>
<div class="section" id="option6">option6</div>
</div>
<div class="blurb hidden" id="option1">
<h1>content for option1</h1>
</div>
<div class="blurb hidden" id="option2">
<h1>content for option2</h1>
</div>
<div class="blurb hidden" id="option3">
<h1>content for option3</h1>
</div>
<div class="blurb hidden" id="option4">
<h1>content for option4</h1>
</div>
<div class="blurb hidden" id="option5">
<h1>content for option5</h1>
</div>
<div class="blurb hidden" id="option6">
<h1>content for option6</h1>
</div>
I'm still fairly new to jQuery, so any advice/pointers is greatly appreciated.
I solved your problem using a custom class and :after CSS styles: http://jsfiddle.net/mblase75/sDrZ2/3/
First, some CSS to append the arrows and convert to uppercase without modifying the text directly:
.uppercase {
text-transform: uppercase;
}
.uppercase.arrowed:after {
content: " >>";
}
Add in some changes to your HTML to utilize data- attributes, remove duplicate IDs and add an arrowed class which the JS toggles:
<div class="nav">
<div class="section arrowed" data-blurb="option1">option1</div>
<div class="section arrowed" data-blurb="option2">option2</div>
<div class="section arrowed" data-blurb="option3">option3</div>
<div class="section arrowed" data-blurb="option4">option4</div>
<div class="section arrowed" data-blurb="option5">option5</div>
<div class="section arrowed" data-blurb="option6">option6</div>
</div>
And finally, a rewrite to optimize your JavaScript a lot:
$('.section').click(function () {
$(this).addClass('uppercase').toggleClass('arrowed')
.siblings('.section').removeClass('arrowed');
$('#'+$(this).data('blurb')).slideToggle()
.siblings('.blurb').hide();
});
Note that the arrowed class is toggled, so it needs to be added initially so that it's toggled off on the first click.