I have mapped an array of words to the button group. and in the state I have an index and a color value
this.state = {
selectedWordIndex:'', //e.g. 3
selectedWordColor:'' //e.g. rgb(137,197,8)
}
the index and the color are set in another function.
var counter = -1;
return this.state.sentenceArray.map((word) => {
counter += 1
return (
<button
key={counter}
type="button"
className="btn btn-default"
style={{}}>{word}</button>);});
how can I change the color of the indexed button?
So if you want to change the color of button with the index === this.state. selectedWordIndex, following code should work.
var counter = -1;
return this.state.sentenceArray.map((word) => {
counter += 1
return (
<button
key={counter}
type="button"
className="btn btn-default"
style={ this.state.selectedWordIndex === counter ?
{ color:this.state.selectedWordColor } :
{}
}
>{word}</button>);});
Related
i am using angular's datepicker to create a booking service.
I am experiencing a huge problem, when I make the reservation I activate a dialog that confirms the outcome of the reservation, if the outcome is positive another dialog opens with the confirmation. when you click on the button 'ok', to close the final dialogue and return to the datepicker, a call starts that takes all the customer's reservations and colors the dates blue.
here the chaos happens:
the dateClass () method inside the appcomponent.ts file is activated several times and cycles the old reservation list and not the new one.
I attached the code:
APPCOMPONENT.HTML
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Clicca sul calendario</mat-label>
<input matInput readonly [matDatepicker]="picker" [(ngModel)]="this.shareDate.myFormattedDate" (dateChange)="openDialog($event)">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker [dateClass]="dateClass()" #picker> </mat-datepicker>
</mat-form-field>
APPCOMPONENT.TS
dateClass() {
return (date: Date): MatCalendarCellCssClasses => {
const unvailableArray = this.shareDate.unavailableDates;
const reservedArray = this.shareDate.reservedDate;
let day = 'freeDate';
for (const element of reservedArray) {
if (date.getFullYear() === element.getFullYear() && date.getMonth() === element.getMonth() &&
date.getDate() === element.getDate()) {
day = 'prenotation';
return day;
}
}
for (const element of unvailableArray) {
if (date.getFullYear() === element.getFullYear() && date.getMonth() === element.getMonth() &&
date.getDate() === element.getDate()) {
day = 'unavailable';
return day;
}
}
return day;
};
}
dialogConfirm.ts
click() {
const devCode = this.getQueryCode.getQueryParameter('d');
this.shareDate.device.deviceId = devCode;
this.postservices.getPrenotationList(this.shareDate.device).subscribe((resp1: GetDataResponse) => {
if (resp1) {
this.shareDate.foundDate = resp1;
for (const element of this.shareDate.foundDate.reservationdDates) {
this.shareDate.reservedDate.push(new Date(element));
}
}
console.log('resp1', resp1);
});
this.postservices.getPrenotationList(this.shareDate.device).subscribe((resp1: GetDataResponse) => {
if (resp1) {
this.shareDate.foundDate = resp1;
for (const element of this.shareDate.foundDate.unavailableDates) {
this.shareDate.unavailableDates.push(new Date(element));
}
}
});
}
I put console.log (), in the dateclass () and in click () when dateclass () starts, the log shows me that I have 3 reservations, when I make a reservation the click () log tells me that I have 4 reservations. but when I close the dialogue, dateclass () activates again and returns me to 3 reservations. if I close and restart the app it shows me 4 reservations ... what happens? what do I have to do?
Don't call function in template.Since dataClass input property expects MatCalendarCellClassFunction,assign function to dateClass property something like this.
component.ts
dateClass = (date: Date): MatCalendarCellCssClasses => {
const unvailableArray = this.shareDate.unavailableDates;
const reservedArray = this.shareDate.reservedDate;
let day = 'freeDate';
for (const element of reservedArray) {
if (date.getFullYear() === element.getFullYear() && date.getMonth() === element.getMonth() &&
date.getDate() === element.getDate()) {
day = 'prenotation';
return day;
}
}
for (const element of unvailableArray) {
if (date.getFullYear() === element.getFullYear() && date.getMonth() === element.getMonth() &&
date.getDate() === element.getDate()) {
day = 'unavailable';
return day;
}
}
return day;
};
component.ts
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Clicca sul calendario</mat-label>
<input matInput readonly [matDatepicker]="picker" [(ngModel)]="this.shareDate.myFormattedDate" (dateChange)="openDialog($event)">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker [dateClass]="dateClass" #picker> </mat-datepicker>
</mat-form-field>
I want change the background color of the selected row after click the button
I tried but change the color of all rows.
This is a similar code.
HTML
<tr *ngFor="let data of (datas$ | async) | filter:authService.filter | paginate: config | orderBy: key : reverse" [ngClass]="{'data-selected':isSelected}">
<td>{{data.id}}</td>
<td>{{data.text}}</td>
<td>
<a class="mr-3" (click)="delete(data.id)"><i class="fa fa-remove"></i>
Remove
</a>
</td>
</tr>
TS
delete(postId) {
this.isSelected=true;
const ans = confirm('TEXT TEXT '+dataid);
if (ans) {
this.dataService.deleteData(postId).subscribe((data) => {
if(data) {
this.showSuccessDelete();
} else {
this.showError();
}
this.isSelected=false;
this.loadDatas();
});
}
}
CSS
.data-selected{
background-color: #e9eaea;
}
Thanks so much
You can add an attribute to your component class and call it selectedRow, which will get the data.id.
selectedRow: number;
delete(postId,numeroDeposito) {
this.selectedRow = postId;
const ans = confirm('TEXT TEXT '+dataid);
if (ans) {
this.dataService.deleteData(postId).subscribe((data) => {
if(data) {
this.showSuccessDelete();
} else {
this.showError();
}
this.isSelected=false;
this.loadDatas();
});
}
}
then in the tr tag use [ngClass]="{'data-selected': selectedRow === data.id}".
You can also take the following approach:
Working Demo
[class.data-selected]="data.isSelected"
and On click event.
(click)="data.isSelected = true";
Rather than declaring a separate isSelected variable. you should introduce is as a property of data object. Ex:
{
id: 1,
name: 'AA',
isSelected: false
}
Then on click you can toggle it when delete function is called with data.id as parameter.
deleteMe(id: string) {
this.data.map(x => x.isSelected = false);
this.data.find(x => x.id === id).isSelected = true;
}
And in html
<tr *ngFor="let item of data" [ngClass]="{selected: item.isSelected}">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td><button (click)="deleteMe(item.id)">delete me</button></td>
</tr>
Here is a minimum example.
You can use conditional styling to achieve this.
<div [className]="( checkSelectedRow(i) ? 'example-class' : 'other-class'"></div>
In Typescript file:
checkSelectedRow(rowNumber) : boolean {
for(int j=0; j<rows.length; j++){
if(j==i){
rows[i]["selected"]=true; return true;
};
}
return false;
}
this can be solve by create an array of selected rows like this
deleteList = []
then when you click remove push the id of the item in the list
delete(id) {
this.deleteList.push(id)
}
then at the template use ngClass directive to set the class if the item id include in the list
<tr *ngFor="let data of list" [ngClass]="{'data-selected':deleteList.includes(data.id)}">
....
</tr>
demo 🚀🚀
I spent a few hours trying to select a single channel from a stereo mp3 file loaded with wavesurfer.js
I finally came up with a solution that's probably not the best, but It works with no problems.
The idea is to simply replace the buffer from the channel I want to mute with zeros. For that, I first store the original data with wavesurfer.backend.buffer.getChannelData(0), and create a zeros array with the same length. Then I replace the content of the channel by using wavesurfer.backend.buffer.copyToChannel(left_zeros, 0).
Works like a charm!
var wavesurfer = WaveSurfer.create({
container: '#waveform',
waveColor: 'darkorange',
progressColor: 'purple',
splitChannels: true,
height: 150,
});
left_data = null;
left_zeros = null;
right_data = null;
right_zeros = null;
wavesurfer.load('./stereo-file.mp3');
wavesurfer.on('ready', function () {
left_data = wavesurfer.backend.buffer.getChannelData(0).map(d => {
return d;
});
left_zeros = left_data.map(d => {
return 0.;
});
right_data = wavesurfer.backend.buffer.getChannelData(1).map(d => {
return d;
});
right_zeros = right_data.map(d => {
return 0.;
});
});
function playLeft() {
wavesurfer.backend.buffer.copyToChannel(left_zeros, 0);
wavesurfer.backend.buffer.copyToChannel(right_data, 1);
}
function playRight() {
wavesurfer.backend.buffer.copyToChannel(left_data, 0);
wavesurfer.backend.buffer.copyToChannel(right_zeros, 1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/wavesurfer.js/1.2.3/wavesurfer.min.js"></script>
<div id="waveform"></div>
<p align="center">
<button class="btn btn-primary" onclick="playLeft()">
<i class="glyphicon glyphicon-play"></i>
Left
</button>
<button class="btn btn-primary" onclick="playRight()">
<i class="glyphicon glyphicon-play"></i>
Right
</button>
<button class="btn btn-primary" onclick="wavesurfer.playPause()">
<i class="glyphicon glyphicon-play"></i>
Play
</button>
</p>
export class PlayerComponent implements OnInit {
wavesurfer: WaveSurfer;
leftGain: any;
rightGain: any;
stateLeft: number = 1;
stateRight: number = 1;
constructor() { }
ngOnInit() {
let audiofile = '../assets/1.mp3';
this.wavesurfer = WaveSurfer.create({
container: '#waveform',
waveColor : 'blue',
progressColor: 'purple',
splitChannels: true,
responsive: true,
normalize: true
});
const splitter = this.wavesurfer.backend.ac.createChannelSplitter(2);
const merger = this.wavesurfer.backend.ac.createChannelMerger(2);
this.leftGain = this.wavesurfer.backend.ac.createGain();
this.rightGain = this.wavesurfer.backend.ac.createGain();
splitter.connect(this.leftGain, 0);
splitter.connect(this.rightGain, 1);
this.leftGain.connect(merger, 0, 0);
this.rightGain.connect(merger, 0, 1);
this.wavesurfer.backend.setFilters([splitter, this.leftGain, merger]);
this.wavesurfer.load(audiofile);
this.wavesurfer.on('play', () => {this.wavesurfer.playPause()});
this.wavesurfer.on('error', (msg) => {
console.log(msg);
});
}
play() {
this.wavesurfer.playPause();
}
right() {
if(this.stateRight == 1)
this.stateRight = 0;
else
this.stateRight = 1;
this.rightGain.gain.value = this.stateRight;
}
left()
{
if(this.stateLeft == 1)
this.stateLeft = 0;
else
this.stateLeft = 1;
this.leftGain.gain.value = this.stateLeft;
}
}
<div id="waveform"></div>
<button class="btn btn-success" (click)="play()">Play/Pause</button>
<button class="btn btn-success" (click)="left()">left</button>
<button class="btn btn-success" (click)="right()">right</button>
I am trying to provide the user with a button as follows:
<select id="test" class="btn btn-default btn-lg">
<option>Admin</option>
<option>Employee</option>
</select>
and based on the option selected, another button will appear with other choices.
Here is my code:
Template.addingUser.helpers({
userType: function () {
if(t.find('#test').value == "Admin"){
}else{
}
},
});
If am not mistaken, I can use something like:
$('#action-button').html('<a class="btn btn-primary edit_button" href="' + Template.addingUser.__helpers.get('item')().sourceCode + '" onclick="">Download</a>');
In the case of an action-button, what about select option?
Or should I follow different approach to serve my purpose?
Your code could work, but it is not how we should do in Meteor. Instead you should make the selected option value a reactive data source, when it changes you could simple you button by helper:
const selectedValue = new ReactiveVar('default_value');
Template.addingUser.helpers({
userType() {
if (selectedValue.get() === 'Admin') {
// return somehitng
} else {
}
},
});
Template.addingUser.events({
'change #test': function(e) {
selectedValue.set(e.target.value);
},
});
In this example, I use ReactiveVar to make selected option value reactive.
Updated
.js
const selectedValue = new ReactiveVar('default_value');
Template.addingUser.helpers({
isAdmin() {
return selectedValue.get() === 'Admin';
},
isNormalUser() {
return selectedValue.get() === 'User';
},
});
Template.addingUser.events({
'change #test': function(e) {
selectedValue.set(e.target.value);
},
});
.html
<template name="addingUser">
<!-- ... -->
{{#if isAdmin}}
<button>Button for admin</button>
{{/if}}
{{#if isNormalUser}}
<button>Button for normal user</button>
{{/if}}
<!-- .. .-->
</template>
I have a form in weather that would have had the condition User add as many lines he needs. He clicks a button and an input is added below the other.
I can do this using jQuery, but I would prefer to use the resources of Meteor. Is it possible to do?
Yes it is, here is an example from one of my apps using the underscore package
In the main template:
<template name="ask">
{{#each answerArray}}
{{>answer}}
{{/each}}
<button id="addItem">Add item</button>
</template>
<template name="answer">
<div class="input-group pt10">
<input class="form-control answer" maxlength="30" placeholder="Answer (max 30 chars)" name="answer" />
<span class="input-group-btn">
<button class="btn btn-danger delButton" id="{{id}}" data-id="{{id}}" type="button">Delete</button>
</span>
</div>
</template>
In the js file:
Template.ask.created = function () {
Session.set('action', 'ask');
answerArray = [ //adding at least two items but it could also be empty
{
id: Random.id(), //using this to give an unique id to the control
value: ''
},
{
id: Random.id(),
value: ''
}
];
Session.set('answerArr', answerArray);
}
And the click event:
Template.ask.events = {
'click #addItem': function () {
var answerArray = Session.get('answerArr');
answerArray.push({
id: Random.id() //just a placeholder, you could put any here
});
Session.set('answerArr', answerArray);
}
}
And finally the helper:
Template.ask.helpers({
answerArray: function () {
var answerArray = Session.get("answerArr")
while (answerArray.length < 2) { //i chose to have it between 2 and 6, you can remove these
answerArray.push({
id: Random.id()
})
}
while (answerArray.length > 6) { // maximum
answerArray.pop();
}
Session.set('answerArr', answerArray);
return answerArray;
}
}
This will reactively increase the number of inputs. After that, if you want to process the inputs you could do the following, on a submit form event or button click:
'click #saveQ': function (e) {
e.preventDefault();
var arr = [];
_.each($('.answer'), function (item) {
if ($(item).val() != '')
arr.push({
answer: $(item).val(), //this you customize for your own purposes
number: 0
})
});
And also if you want to delete an input from the page you can use:
Template.answer.events = {
'click .delButton': function (e) {
var thisId = $(e.target).attr("id");
var answerArray = Session.get('answerArr');
var filteredArray = _.filter(answerArray, function (item) {
return item.id != thisId;
});
Session.set('answerArr', filteredArray);
}
}