Update:
I checked if setDate() is called from ngOnInit: it is.
Also I specified the variables: rentalStartInput is an string Array and contains the real dates with I get from the other component (see picture below).
rentalStart is a Date, right now it is hard-coded, which I want to change. rentalStart should countain the start day of a range which I got from rentalStartInput. Current I write it manually, to see if highlighting dates works. (it does)
Update end
I'm a beginner with typescript/angular and I'm having the problem of not being able to access variables.
I have some rentals which have a start and end date. I want to display those in a calendar like the following:
Currently I get it out that the range is displayed as in the picture, but only hard-coded.
TypeScript:
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css']
})
export class CalendarComponent implements OnInit {
// #Input() rentalStartInput: String[]; //error: Property 'rentalStartInput' has no initializer and is not definitely assigned in the constructor.
#Input() rentalStartInput: String[] = [];
#Input() rentalEndInput: String[] = [];
rentalStart: Date = new Date(2023-1-1);
rentalEnd: Date = new Date(2023-1-1);
getDaysFromDate(month: number, year: number) {
const startDate = moment(`${year}/${month}/01`)
const endDate = startDate.clone().endOf('month')
this.dateSelect = startDate;
const diffDays = endDate.diff(startDate, 'days', true)
const numberDays = Math.round(diffDays);
this.monthSelect = Object.keys([...Array(numberDays)]).map((a: any) => {
a = parseInt(a) + 1;
const dayObject = moment(`${year}-${month}-${a}`);
return {
name: dayObject.format("dddd"),
value: a,
indexWeek: dayObject.isoWeekday(),
selected: this.isInRange(a, month, year),
};
});
}
isInRange(day: any, month: any, year: any) {
let rangeDay = new Date(year, month - 1, day);
this.rentalStart = new Date(2023, 0, 6); //hard-coded, what I want to change
this.rentalEnd = new Date(2023, 0, 17)
let rentalRange = moment.range(this.rentalStart, this.rentalEnd);
return rentalRange.contains(rangeDay); //true if day is in range -> highlighted in ui
}
}
When I try to get access to variables rentalStartInput and rentalEndInput it doesnt work. I want to replace rentalStartand rentalEnd with them. I also don't want to do the assignment within the method, because then it's done 31 times. But when I change it to a new method, rentalStart and rentalEnd are undefined.
How can I assign both variables and use them in isInRange?
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css']
})
export class CalendarComponent implements OnInit {
#Input() rentalStartInput: String[] = [];
#Input() rentalEndInput: String[] = [];
rentalStart: Date = new Date(2023-1-1);
rentalEnd: Date = new Date(2023-1-1);
ngOnInit(): void {
this.setDate();
}
setDate(){
this.rentalStart = new Date(2023, 0, 6);
this.rentalEnd = new Date(2023, 0, 17);
console.log('setDate'); //check if it is ever called from ngOnInit (it is)
}
isInRange(day: any, month: any, year: any) {
console.log(this.rentalStart); // undefined
(...)
}
}
I get the real dates from another component via #Input(). They are in separate variables: rentalStartInput and rentalEndInput
In console they look like this:
What i'm trying to do is to generate range objects to check if a day is included.
First of all, I fail getting access to the dates.
console.log(this.rentalStartInput) // see picture
console.log(JSON.stringify(this.rentalStartInput)) // []
console.log(this.rentalStartInput[0]) // undefined
console.log(Object.keys(this.rentalStartInput).length) // 0
console.log(this.rentalStartInput.length) // 0
console.log(this.rentalStartInput['1']) // undefined
What possibilities are there to access the data? I cant do a for loop unless I know the length of the array.
I hope my problem is understandable. I can provide more code if necessary.
Thank you very much for any kind of help!
Related
I am trying to get a correct outcome on difference of two dates. But when I do this I am getting a result such as (ex.10211438742389) instead of 1, 2, 3, 4, etc.. This is my JavaScript code.
import Division from '#salesforce/schema/User.Division';
import { LightningElement, track } from 'lwc';
export default class LightningExampleInputDate extends LightningElement {
#track date1;
#track date2;
#track result;
datehandler1(event) {
this.date1 = Date.now();
console.log(event.target.value)
}
datehandler2(event) {
this.date2 = new Date(event.target.value);
console.log(event.target.value);
}
resulthandler() {
this.result = Math.abs(this.date2 - this.date1);
console.log(this.result);
}
}
I am expecting a shorter value to come out when I check the difference in-between two dates.
Dates in javascripts is a representation of milliseconds starting from the epoch date, which is 1st of Jan 1970.
If you want to calculate the difference of two dates in days, you could try this solution: https://stackoverflow.com/a/3224854/1964104
I am trying to implement a function which would eventually return a concatenated list.
When the user selects the node, an EventEmitter emits it. It is in the TreeNode format:
displayName: string;
children: TreeNode<T>[];
selected: boolean;
collapsed?: boolean;
indeterminate: boolean;
selectable: boolean;
value: T;
I am then passing this node as an input to my function. However, according to my current implementation, I get multiple lists (one for every node that is selected).
I wanted just one concatenated list. When I select a node, "returnTrees" will have the correct list. On selection of another node, console.log(returnTrees) will display the previous list(for first selected node) as well as the new list.
slice.component.ts:
public onSliceChange(event:TreeNode<string>):void {
if(event.selected || event.indeterminate) {
this.selections.push(event);
this.selections.forEach(tree => {
let selectedNodes:TreeNode<string>[] = tree.children.filter(child => child.selected || child.indeterminate);
let returnTrees:TreeNode<string>[] = [];
selectedNodes.forEach(node => {
var tempTree:TreeNode<string> = new TreeNode<string>();
tempTree.displayName = node.displayName;
tempTree.value = tree.value;
tempTree.children = [];
node.children.forEach(child => tempTree.children = tempTree.children.concat(TreeNode.getAllCheckedNodes(child)));
returnTrees.push(tempTree);
});
console.log(returnTrees); //prints all lists for all selected nodes
});
}
}
I tried adding :
tempList: TreeNode<string>[] =[];
this.tempList.concat(returnTrees);
But "this.tempList" always is empty in this case (even on node selection).
How can I combine the lists and get a single list? Is this possible?
Any help is appreciated!
I have this:
init(userId: string = this.authProvider.currentUserId) {
this._subscription.add(this.db.list(`meetings/${userId}`)
.subscribe((meetings: any[]) => {
this._meetings = meetings.map((meeting) => {
meeting.Date = meeting.Date;
meeting.Ends = moment.tz(meeting.Ends, 'HH:mm', meeting.Location.TimeZone).local().format('HH:mm');
meeting.Starts = moment.tz(meeting.Starts, 'HH:mm', meeting.Location.TimeZone).local().format('HH:mm');
return Meeting.Parse(meeting);
});
}));
}
On any change from firebase, meeting.Starts, meeting.Ends values are preserved after being parsed by moment.tz.
So assuming on first subscription meeting.Starts is 11:00. After doing meeting.Starts = moment.tz... which will result in say 13:00 then next time anything happens on firebase end and the subscription is triggered, the value of Starts becomes 15:00 assuming the timezone adds 2 hours.
(The value in firebase is correct...) What's happening?
You appear to be using AngularFire2.
The problem is that you are mutating the items in the list. When changes occur, AngularFire2 updates only the items that are affected by the change. However, you are mutating all of the items - so moment.tz will be re-applied to any items that have not changed.
One solution would be to not mutate the items:
init(userId: string = this.authProvider.currentUserId) {
this._subscription.add(this.db.list(`meetings/${userId}`)
.subscribe((meetings: any[]) => {
this._meetings = meetings.map(meeting => Meeting.Parse({
...meeting,
Ends: moment.tz(meeting.Ends, 'HH:mm', meeting.Location.TimeZone).local().format('HH:mm'),
Starts: moment.tz(meeting.Starts, 'HH:mm', meeting.Location.TimeZone).local().format('HH:mm');
}));
});
}
Or, without the spread properties syntax:
init(userId: string = this.authProvider.currentUserId) {
this._subscription.add(this.db.list(`meetings/${userId}`)
.subscribe((meetings: any[]) => {
this._meetings = meetings.map(meeting => Meeting.Parse(
Object.assign({}, meeting, {
Ends: moment.tz(meeting.Ends, 'HH:mm', meeting.Location.TimeZone).local().format('HH:mm'),
Starts: moment.tz(meeting.Starts, 'HH:mm', meeting.Location.TimeZone).local().format('HH:mm');
})
));
});
}
I'm building a simple weekly calendar component for my app and I'm struggling to find a way for creating the weeks navigation. Here's what I have so far:
/week-view/component.js
import Ember from 'ember';
export default Ember.Component.extend({
firstDay: moment().startOf('week'),
days: Ember.computed('firstDay', function() {
let firstDay = this.get('firstDay').subtract(1, 'days');
let week = [];
for (var i = 1; i <= 7; i++) {
var day = firstDay.add(1, 'days').format('MM-DD-YYYY');
week.push(day);
}
return week;
}),
actions: {
currentWeek() {
this.set('firstDay', moment().startOf('week'));
},
previousWeek() {
this.set('firstDay', moment().startOf('week').subtract(7, 'days'));
},
nextWeek() {
this.set('firstDay', moment().startOf('week').add(7, 'days'));
}
}
});
/week-view/template.hbs
<button {{action "previousWeek"}}>previous</button>
<button {{action "currentWeek"}}>current week</button>
<button {{action "nextWeek"}}>next</button>
<ul>
{{#each days as |day|}}
<li>{{day}}</li>
{{/each}}
</ul>
At the moment it works to navigate one week before and one after the current week only. Any idea on how to make this work for an unlimited number of weeks is greatly appreciated. Thanks in advance.
I think you shouldn't change your firstDay property while prepairing week array (in the computed function). It overrides momentjs state. Computed property in this case should just read firstDay property without affecting changes to it.
Also in your previous and next week actions you don't have to create new momentjs objects. You can easily operate on previously created firstDay property, for example.
this.get('firstDay').subtract(7, 'days');
But in this case, state of momentjs have changed, but emberjs doesn't see any changes. That is because your firstDay property doesn't really changed (and computed property is set to check only firstDay, it doesn't work deeply). In fact firstDay property is just reference to momentjs object, and that object has been changed, not the reference. But luckily you can manually force emberjs to reload any computed properties based on any property in this way:
this.notifyPropertyChange('firstDay');
So little bit refactored working example can looks like:
import Ember from 'ember';
export default Ember.Component.extend({
selectedWeek: moment().startOf('week'),
days: Ember.computed('selectedWeek', function() {
let printDay = this.get('selectedWeek').clone();
let week = [];
for (var i = 1; i <= 7; i++) {
week.push(printDay.format('MM-DD-YYYY'));
printDay.add(1, 'days');
}
return week;
}),
actions: {
currentWeek() {
this.set('selectedWeek', moment().startOf('week'));
},
previousWeek() {
this.get('selectedWeek').subtract(7, 'days');
this.notifyPropertyChange('selectedWeek');
},
nextWeek() {
this.get('selectedWeek').add(7, 'days');
this.notifyPropertyChange('selectedWeek');
}
}
});
EmberJSBin here
I have a component which needs to perform a given operation when any of its values are changed, but the observer I created does not fire:
export default Ember.Component.extend({
taxes: null,
NOAYears: 2,
NOAValues: Ember.computed("NOAYears", function() {
var NOAs = [],
lastYear = new Date().getFullYear() - 1;
for (var year = 0; year < this.get("NOAYears"); year++) {
NOAs.push({year: lastYear - year, value: 0});
}
return NOAs;
}),
NOAYearsChanged: function() {
// does not fire when any of the values change
}.observes("NOAValues.#each.value")
});
In the component template, I am binding via the {{#each}} iterator:
{{#each NOAValues as |year|}}
<label for="{{year.year}}-value">{{year.year}}</label>
{{input min="0" step="any" value=year.value required=true placeholder="Yearly Income"}}
{{/each}}
How can I get my observer to fire when any of the value properties in NOAValues is changed?
This issue has been verified as a bug, caused by legacy code, which interprets any property name beginning with a capital letter (i.e. PascalCase) as either a global or a Class name reference... rendering the property unobservable.
Source: https://github.com/emberjs/ember.js/issues/10414
It seems like efforts will be made to fix it in some upcoming releases.
In order to observe property changes, you need to use a setter for a given property. I think you introduce a NOA model that extends Ember.Object it should be sufficient. For example:
// file app/model/noa.js
export default Ember.Object.extend({
year: undefined,
value: undefined
});
and then replace this:
for (var year = 0; year < this.get("NOAYears"); year++) {
NOAs.push({year: lastYear - year, value: 0});
}
with
for (var year = 0; year < this.get("NOAYears"); year++) {
NOAs.push(app.model.noa.create({year: lastYear - year, value: 0}));
}
You should see some property changes.