<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Angular &#8211; CodePills.com</title>
	<atom:link href="https://codepills.com/tag/angular/feed/" rel="self" type="application/rss+xml" />
	<link>https://codepills.com</link>
	<description>Helping you make a better code</description>
	<lastBuildDate>Sat, 23 Mar 2024 14:11:03 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>How to create a custom range calendar filter for Angular PrimeNg data turbo table</title>
		<link>https://codepills.com/how-to-create-a-custom-range-calendar-filter-for-angular-primeng-data-turbo-table/</link>
					<comments>https://codepills.com/how-to-create-a-custom-range-calendar-filter-for-angular-primeng-data-turbo-table/#comments</comments>
		
		<dc:creator><![CDATA[Andrej Buday]]></dc:creator>
		<pubDate>Fri, 14 Aug 2020 17:48:34 +0000</pubDate>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Angular]]></category>
		<category><![CDATA[calendar]]></category>
		<category><![CDATA[custom filter]]></category>
		<category><![CDATA[ngPrime]]></category>
		<category><![CDATA[PrimeNg]]></category>
		<category><![CDATA[range]]></category>
		<category><![CDATA[table]]></category>
		<guid isPermaLink="false">https://codepills.com/?p=1065</guid>

					<description><![CDATA[In this article, we will look at how to create a custom filter for PrimeNg calendar selection with a date range <a href="https://codepills.com/how-to-create-a-custom-range-calendar-filter-for-angular-primeng-data-turbo-table/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>Let&#8217;s look at how to implement the Angular selection range for the newest Angular PrimeNg version. This tutorial was developed on <b>v10.0.0-rc-1</b> version.</p>
<p><span id="more-1065"></span></p>
<p>I had difficulty finding a proper solution for range selection in the PrimeNg turbo data table for the newest version. Therefore I have decided to create a workaround. For the time selection, each click event on the calendar panel fire only one piece of data &#8211; the currently selected date. So the calendar range is stateless. You need to remember somehow to keep in memory what date was fired before and implement this logic in a custom filter.</p>
<p>I observed that there are several rules according to which <code>p-calendar</code> component behave when the selection mode <code>"range"</code> is selected. Here are my findings according to which I programmed the logic:</p>
<ul>
<li>At first, the calendar component has an empty, undefined selection.</li>
<li>If one date is selected, only one date is fired on click event.</li>
<li>If the same date as date previously selected is selected, new date (which is the same as previously selected date) is fired on click event.</li>
<li>If a date before the already selected date is selected, the selection is cancelled and earlier date is fired on click event.</li>
<li>If a date after the already selected date is selected, the selection range is visible.</li>
<li>If any new date is selected after the selection range is visible, a new date is selected, fired upon click event and selection range is cancelled.</li>
</ul>
<p>When all this wrote down, here is the implementation code for component and custom filter:</p>
<p><b>record-list.component.html</b></p>
<pre><code class="language-html">&#60;p-table #dt [value]="records" sortMode="multiple" [paginator]="true" [rowsPerPageOptions]="rowsPerPageTable" [rows]="rowsPerTable" [showCurrentPageReport]="true" [(first)]="page" styleClass="p-datatable-striped" currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"&#62;
    &#60;ng-template pTemplate="header"&#62;
        &#60;tr class="ui-table-thead"&#62;
            &#60;th [ngStyle]="{'width':'50%'}" pSortableColumn="createdDate"&#62;Created &#60;p-sortIcon field="createdDate"&#62;&#60;/p-sortIcon&#62;&#60;/th&#62;
            &#60;th [ngStyle]="{'width':'50%'}" pSortableColumn="info"&#62;Info &#60;p-sortIcon field="info"&#62;&#60;/p-sortIcon&#62;&#60;/th&#62;
        &#60;/tr&#62;
        &#60;tr class="ui-table-thead"&#62;
            &#60;th scope="col"&#62;
                &#60;p-calendar (onSelect)="onDateSelect($event)" [style]="{'width':'100%'}" selectionMode="range" [readonlyInput]="true" (onClearClick)="onDateClear($event)" [showButtonBar]="true" placeholder="Created Date" class="p-column-filter" dateFormat="yy-mm-dd"&#62;&#60;/p-calendar&#62;
            &#60;/th&#62;
            &#60;th scope="col"&#62;
                &#60;input pInputText type="text" [style]="{'width':'100%'}" (input)="dt.filter($event.target.value, 'info', 'contains')" placeholder="Info"&#62;
            &#60;/th&#62;
        &#60;/tr&#62;
    &#60;/ng-template&#62;

    &#60;ng-template pTemplate="body" let-rowData&#62;
        &#60;tr ng-repeat="rowData in let-rowData" ng-click="showClient(rowData)"&#62;
            &#60;td&#62;{{ rowData.createdDate }}&#60;/td&#62;
            &#60;td&#62;{{ rowData.info }}&#60;/td&#62;
        &#60;/tr&#62;
    &#60;/ng-template&#62;

&#60;/p-table&#62;</code></pre>
<p><b>record-list.component.ts</b></p>
<pre><code class="language-typescript">export class RecordListComponent implements OnInit {

    public records: IssueShortInfo[];

    @ViewChild('dt') table: Table;

    cols: any[];
    dateRangeStart: string;
    dateRangeEnd: string;

    rowsPerPageTable: number[] = [25, 50, 100, 200];

    page: number = 0;
    rowsPerTable: number = 25;

    constructor(private recordService: RecordService) {}

    ngOnInit() {

        this.recordService.getAllRecords().subscribe(page => {
            this.getRecords(page);
        }, (error => {
            console.log(error)
        }));

        this.cols = [
            {field: 'id', header: 'Id'},
            {field: 'createdDate', header: 'Created Date'},
            {field: 'info', header: 'Info'}
        ];

        FilterUtils['customCreatedDateFilter'] = (value: string, filter) => {

            if (this.dateRangeStart === value && this.dateRangeEnd === undefined) {
                return true;
            }

            if (this.dateRangeStart === value || this.dateRangeEnd === value) {
                return true;
            }

            if (this.dateRangeStart !== undefined && this.dateRangeEnd !== undefined &&
                moment(this.dateRangeStart).isBefore(value) && moment(this.dateRangeEnd).isAfter(value)) {
                return true;
            }

            return false;
        };
    }

    getRecords(page: Page<IncomingRecordDTO>) {
        this.records = page.content.map(incomingRecordDTO => new Record(incomingRecordDTO));
    }

    onDateSelect($event) {

        const eventDate = this.formatDate($event);

        if (this.dateRangeStart === undefined) {
            this.dateRangeStart = eventDate;
        } else if (moment($event).isBefore(this.dateRangeStart)) {
            this.dateRangeStart = eventDate;
            this.dateRangeEnd = undefined;
        } else if (moment($event).isSame(this.dateRangeStart) && this.dateRangeStart !== undefined && this.dateRangeEnd === undefined) {
            this.dateRangeEnd = eventDate;
        } else if (moment($event).isSame(this.dateRangeStart) && this.dateRangeStart !== undefined && this.dateRangeEnd !== undefined) {
            this.dateRangeStart = eventDate;
            this.dateRangeEnd = undefined;
        } else if (moment($event).isAfter(this.dateRangeStart) && this.dateRangeStart !== undefined && this.dateRangeEnd !== undefined) {
            this.dateRangeStart = eventDate;
            this.dateRangeEnd = undefined;
        } else {
            this.dateRangeEnd = eventDate;
        }

        this.table.filter(eventDate, 'createdDate', 'customCreatedDateFilter');
    }

    onDateClear($event) {
        this.dateRangeStart = undefined;
        this.dateRangeEnd = undefined;
        this.table.filter('', 'createdDate', 'equals');
    }

    formatDate(date) {
        let month = date.getMonth() + 1;
        let day = date.getDate();

        if (month < 10) {
            month = '0' + month;
        }

        if (day < 10) {
            day = '0' + day;
        }
        return date.getFullYear() + '-' + month + '-' + day;
    }

    customCreatedDateArrayFilter(event) {
        this.table.filter(event, 'createdDate', 'customCreatedDateFilter');
    }

}</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://codepills.com/how-to-create-a-custom-range-calendar-filter-for-angular-primeng-data-turbo-table/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Refactoring function for the least amount of lines</title>
		<link>https://codepills.com/refactoring-function-for-the-least-amount-of-lines/</link>
					<comments>https://codepills.com/refactoring-function-for-the-least-amount-of-lines/#respond</comments>
		
		<dc:creator><![CDATA[Andrej Buday]]></dc:creator>
		<pubDate>Sat, 22 Jun 2019 16:20:34 +0000</pubDate>
				<category><![CDATA[Refactoring]]></category>
		<category><![CDATA[Angular]]></category>
		<category><![CDATA[dropdown]]></category>
		<category><![CDATA[functional programming]]></category>
		<category><![CDATA[refactoring]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[user]]></category>
		<guid isPermaLink="false">https://codepills.com/?p=1021</guid>

					<description><![CDATA[I had the opportunity to review a small piece of code. I took code review personally and challenged myself to write the shortest solution possible. <a href="https://codepills.com/refactoring-function-for-the-least-amount-of-lines/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>I had the opportunity to review a small piece of code. From the first look, I knew this is a beautiful example ready for refactoring.</p>
<p><span id="more-1021"></span></p>
<p>I took code review little bit personally and challenged myself to write the least amount of line; if I can write the shortest solution possible.</p>
<p>Following code is a method which based on the event input is searching through the list of roles and produce a filtered list of roles in the dropdown selection for Angular form.</p>
<pre><code class="language-typescript">searchRoles(event) {
    let roleList = [];
    this.rolesFiltered = User.ROLES.filter(role =&gt;
        role.label.toLocaleLowerCase().includes(event.query.toLocaleLowerCase());
    if (this.editForm.value.roles) {
        this.rolesFiltered.forEach(filteredRole =&gt; {
            const isInForm = this.editForm.value.roles.some(formRole =&gt; {
                return filteredRole.value.includes(formRole.value);
            });
            if (!isInForm) {
                roleList.push(filteredRole);
            }
        });
    } else {
        roleList = this.rolesFiltered;
    }
    this.rolesFiltered = roleList;
}</code></pre>
<p>The original code had 18 lines of code. Can you find anything odd with it? Do you think this is the shortest way possible? Read further and if you have any more suggestion or ideas for this piece of code, please share them in comments.</p>
<p>I see at least 3 things which are wrong with this code.</p>
<ol>
<li>There is a loop in a loop. Therefore, finding the roles to display is equal to O(n<sup>2</sup>). I had a hunch that this can be decreased to down O(n).</li>
<li>It seems there is too much unnecessary if-else nesting.</li>
<li>Assigning a value on the end of the code seems also as an inappropriate solution. It is connected with a 2nd point, and I also had another hunch this can be mitigated.</li>
</ol>
<pre><code class="language-typescript">searchRoles(event) {
    this.dropdownRoles = User.ROLES.filter(role =&gt;
        role.label.toLocaleLowerCase().includes(event.query.toLocaleLowerCase())
    );
    if (this.editForm.value.roles) {
        let tempRoleList = [];
        this.dropdownRoles.forEach(dropdownRole =&gt; {
            if (!this.editForm.value.roles.includes(dropdownRole)) {
              tempRoleList.push(dropdownRole);
            }
        });
        this.dropdownRoles = tempRoleList;
    }
}</code></pre>
<p>First of all, I tried to get rid of the temporary variable. It is necessary now. But only in case if you want to temporary store the case that there is already a role selected and you want to pick up roles from the shortened general list of roles.</p>
<p>The first iteration had 13 lines of code.</p>
<pre><code class="language-typescript">searchRoles(event) {
    this.dropdownRoles = User.ROLES.filter(role =&gt;
        role.label.toLocaleLowerCase().includes(event.query.toLocaleLowerCase())
    );
    if (this.editForm.value.roles) {
        var i = this.dropdownRoles.length;
        while (i--) {
            if (this.editForm.value.roles.includes(this.dropdownRoles[i])) {
                this.dropdownRoles.splice(i, 1);
            }
        }
    }
}</code></pre>
<p>Then I have decided that looping over all dropdown roles so it can help me save some more instructions if it is made correctly. Looping backward I also cut off all used roles and I was getting back only unselected roles in the dropdown menu.</p>
<p>Looping backward reduced the lines even more into 12 lines of code.</p>
<pre><code class="language-typescript">searchRoles(event) {
    this.dropdownRoles = User.ROLES.filter(role =&gt;
      role.label.toLocaleLowerCase().includes(event.query.toLocaleLowerCase())
    );
    if (this.editForm.value.roles) {
        for (var i = this.dropdownRoles.length - 1; i &gt;= 0; i--) {
            if (this.editForm.value.roles.includes(this.dropdownRoles[i])) {
                this.dropdownRoles.splice(i, 1);
            }
        }
    }
}</code></pre>
<p>I googled the possibility to make this code shorter and eventually it is possible by refactoring <code>while</code> loop and by using TypeScript syntactic sugar to assign variable for dropdown list in <code>for</code> cycle.</p>
<p>Rewriting <code>while</code> to <code>for</code> in TypeScript brought reduction to 11 lines of code.</p>
<pre><code class="language-typescript">searchRoles(event) {
    function filterRoles(role, editForm) {
        if (!editForm.includes(role)) {
            return role;
        }
    }
    this.dropdownRoles = User.ROLES.filter(role =&gt;
        role.label.toLocaleLowerCase().includes(event.query.toLocaleLowerCase())
    );
    if (this.editForm.value.roles) {
        this.dropdownRoles = this.dropdownRoles.filter(dropdownRole =&gt; filterRoles(dropdownRole, this.editForm.value.roles));
    }
}</code></pre>
<p>When I didn&#8217;t know how to minimize it further I asked myself a different question &#8211; Is possible to rewrite this code in functional paradigm?</p>
<p>So I turned to functional programming and decided to use the same idea for filtering as in initial querying of user input. I have created a standalone local function which took 2 arguments.</p>
<p>Rewriting the solution in a functional way increased method back to 12 lines of code.</p>
<pre><code class="language-typescript">searchRoles(event) {
    this.dropdownRoles = User.ROLES.filter(role =&gt;
        role.label.toLocaleLowerCase().includes(event.query.toLocaleLowerCase())
    );
    if (this.editForm.value.roles) {
        this.dropdownRoles = this.dropdownRoles.filter(dropdownRole =&gt; {
            if (!this.editForm.value.roles.includes(dropdownRole)) {
                return dropdownRole;
            }
        });
    }
}</code></pre>
<p>However, removing the function and making it anonymous decreased the code length to 11 lines. As a side-effect, the solution is rewritten more robustly and functionally.</p>
<p>While I played with other versions of functional refactoring, I picked up the last one because it was the most readable solution. You know, less code is better (easier maintenance, less prone to errors, etc.). But we need to remember that not every code is readable code.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://codepills.com/refactoring-function-for-the-least-amount-of-lines/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Angular calendar datepicker creates incorrect date one day behind the selection</title>
		<link>https://codepills.com/angular-calendar-datepicker-creates-incorrect-date-one-day-behind-the-selection/</link>
					<comments>https://codepills.com/angular-calendar-datepicker-creates-incorrect-date-one-day-behind-the-selection/#respond</comments>
		
		<dc:creator><![CDATA[Andrej Buday]]></dc:creator>
		<pubDate>Sat, 22 Jun 2019 12:51:03 +0000</pubDate>
				<category><![CDATA[Bug hunt]]></category>
		<category><![CDATA[Angular]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://codepills.com/?p=1015</guid>

					<description><![CDATA[In this article, we will be looking at Angular datepicker and transferring the correct date through the REST endpoint. <a href="https://codepills.com/angular-calendar-datepicker-creates-incorrect-date-one-day-behind-the-selection/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[<p>I was working on the bug fix task, which aimed to solve an extraordinary issue at first sight. In the monolithic Angular-Spring application, I choose a specific date at the front end with an Angular calendar datepicker. However, the database suddenly saved one day before the initially selected date.</p>
<p><span id="more-1015"></span></p>
<p>I started investigating the cause of the issue. First, I examined with Spring backend REST endpoint call with the breakpoint. The entity with the date was already coming incorrect from the Angular frontend. The backend endpoint on entry showed incorrect data, so the error was automatically not in the backend code.</p>
<p>At the frontend call for the backend REST endpoint, I also used <code>JSON.stringify(object)</code> to check if the produced entity which was leaving the frontend to the backend was correct. What I found was that it was also already incorrect.</p>
<p>Consequently, the issue happened somewhere between the user browser and Angular call for the backend. In this way, I also eliminated the possibility that the problem was somewhere in the Spring JSON conversion library (I used Jackson).</p>
<p>In the end, I figured it out. The issue was in class, which was migrating datepicker form data into the object. While the Angular calendar datepicker <u>collect the date from the browser also with local time zone</u> as a string, data to JSON ware pushed as a JavaScript <code>Date</code> class without a time zone. So if you, for example, pickup up any date, it was selected as the date for midnight with the timezone offset and transferred from string to <code>Date</code> as the day before due the offset counted as date subtraction.</p>
<p>I was working in Central Europe. In the case of Central Europe (CET), where I was working, the browser records +1 hour from GMT in datepicker based on local PC time settings. So if I pick up the date, hours and minutes are selected for midnight (00:00). However, <code>Date</code> class takes the datepicker string and subtract the negative offset from midnight and set a selected date for a day before.</p>
<p>This is the Angular&#8217;s datepicker component HTML code from the component form:</p>
<pre><code class="language-typescript">&lt;div class="ui-g-6"&gt;
    &lt;div&gt;
        &lt;label for="startDate"&gt;Start Date&lt;/label&gt;
    &lt;/div&gt;
    &lt;vrm-form-field [control]="editForm.controls['startDate']"&gt;
        &lt;p-calendar id="startDate"
            [formControlName]="'startDate'"
            dateFormat="yy-mm-dd"
            yearRange="1900:2100"&gt;
        &lt;/p-calendar&gt;
    &lt;/vrm-form-field&gt;
&lt;/div&gt;</code></pre>
<p>Following static function created an object from form datepicker which was pushed to REST endpoint before the fix:</p>
<pre><code class="language-typescript">static mapFromFormData(form: any) {
    return new ImportantDate(form.startDate);
}</code></pre>
<p>To fix the problem, I created a workaround. I made a Utility class with <code>moment library</code>, which takes a datepicker string and select only required date information.</p>
<pre><code class="language-typescript">export class Utils {
  public static formatDate(date: any): string {
    if (date === undefined || date === null) {
      return undefined;
    } else {
      return moment(date).format('YYYY-MM-DD');
    }
  }
}</code></pre>
<p>You can see the implementation of the static Utils method, which fixed the date.</p>
<pre><code class="language-typescript">static mapFromFormData(form: any) {
    return new ImportantDate(
        Utils.formatDate(form.startDate)
    );
}</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://codepills.com/angular-calendar-datepicker-creates-incorrect-date-one-day-behind-the-selection/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
