Base solution for your next web application

Activities of "cashonledger"

Hi,

we've used the AspNetZero RAD Tool to auto-generate our html and ts files along with the entities.

Is there any very basic example on how have the html & ts look like for having an editable table? I read the example on the documentation page of PrimeNg here but the the html pages created by AspNetZero RAD Tool are quite more code-heavy.

Here is an example html page with only one entity:

<div [@routerTransition]>
    <div class="kt-subheader kt-grid__item">
        <div class="kt-subheader__main">
            <h3 class="kt-subheader__title">
                <span>{{l("Anlasses")}}</span>
            </h3>
            <span class="kt-subheader__separator kt-subheader__separator--v"></span>
            <span class="kt-subheader__desc">
                {{l("AnlassesHeaderInfo")}}
            </span>
        </div>
        <div class="kt-subheader__toolbar">
            <div class="kt-subheader__wrapper">
				<button (click)="exportToExcel()" class="btn btn-outline-success"><i class="fa fa-file-excel"></i> {{l("ExportToExcel")}}</button>
                <button *ngIf="isGranted('Pages.Administration.Anlasses.Create')" (click)="createAnlass()" 
			class="btn btn-primary blue"><i class="fa fa-plus"></i> {{l("CreateNewAnlass")}}</button>
            </div>
        </div>
    </div>
    <div class="kt-content">
        <div class="kt-portlet kt-portlet--mobile">
            <div class="kt-portlet__body">
			
                <form class="kt-form" autocomplete="off">
                    <div>
                        <div class="row align-items-center">
                            <div class="col-xl-12">
                                <div class="form-group m-form__group align-items-center">
                                    <div class="input-group">
                                        <input [(ngModel)]="filterText" name="filterText" autoFocus class="form-control m-input" [placeholder]="l('SearchWithThreeDot')" type="text">
                                        <span class="input-group-btn">
                                            <button (click)="getAnlasses()" class="btn btn-primary" type="submit"><i class="flaticon-search-1"></i></button>
                                        </span>
                                    </div>
                                </div>
                            </div>
                        </div>
						 <div class="row" [hidden]="!advancedFiltersAreShown">
						 	<div class="col-md-12">
						         <div class="kt-separator kt-separator--border-dashed"></div>
						     </div>


							<div class="col-md-3">
								<div class="form-group">
									<label for="AnlassTypFilter">{{l("AnlassTyp")}}</label>
									<input type="text" class="form-control" id="AnlassTypFilter" name="anlassTypFilter" [(ngModel)]="anlassTypFilter">
								</div>
                            </div>

                        </div>
                        <div class="row mb-2">
                            <div class="col-sm-12">
                                <span class="clickable-item text-muted" *ngIf="!advancedFiltersAreShown" (click)="advancedFiltersAreShown=!advancedFiltersAreShown"><i class="fa fa-angle-down"></i> {{l("ShowAdvancedFilters")}}</span>
                                <span class="clickable-item text-muted" *ngIf="advancedFiltersAreShown" (click)="advancedFiltersAreShown=!advancedFiltersAreShown"><i class="fa fa-angle-up"></i> {{l("HideAdvancedFilters")}}</span>
                            </div>
                        </div>
                    </div>
                </form>

                <div class="row align-items-center">
                    <!--<Primeng-Datatable-Start>-->
                    <div class="primeng-datatable-container col-12"
                         [busyIf]="primengTableHelper.isLoading">
                        <p-table #dataTable
                                     (onLazyLoad)="getAnlasses($event)"
                                     [value]="primengTableHelper.records"
                                     rows="{{primengTableHelper.defaultRecordsCountPerPage}}"
                                     [paginator]="false"
                                     [lazy]="true"
                                     [scrollable]="true"
                                     ScrollWidth="100%"
                                     [responsive]="primengTableHelper.isResponsive"
                                     [resizableColumns]="primengTableHelper.resizableColumns">
                            <ng-template pTemplate="header">
                                <tr>
                                    <th style="width: 130px" [hidden]="!isGrantedAny('Pages.Administration.Anlasses.Edit', 'Pages.Administration.Anlasses.Delete')">{{l('Actions')}}</th>
                                    <th style="width: 150px" pSortableColumn="anlassTyp">
                                        {{l('AnlassTyp')}}
                                        <p-sortIcon field="anlass.anlassTyp"></p-sortIcon>
                                    </th>

                                </tr>
                            </ng-template>
							<ng-template pTemplate="body" let-record="$implicit" let-rowData>
                                <tr>
                                    <td style="width: 130px"
                                        [hidden]="!isGrantedAny('Pages.Administration.Anlasses.Edit', 'Pages.Administration.Anlasses.Delete')">
                                       <div class="btn-group dropdown" dropdown container="body">
                                            <button class="dropdown-toggle btn btn-sm btn-primary" dropdownToggle>
                                                <i class="fa fa-cog"></i><span class="caret"></span> {{l("Actions")}}
                                            </button>
												<ul class="dropdown-menu"  *dropdownMenu>
												<li>
													<a href="javascript:;"
														(click)="viewAnlassModal.show(record)">{{l('View')}}</a>
												</li>
												<li>
													<a href="javascript:;" *ngIf="permission.isGranted('Pages.Administration.Anlasses.Edit')"
														(click)="createOrEditAnlassModal.show(record.anlass.id)">{{l('Edit')}}</a>
												</li>
												<li>
											        <a href="javascript:;" *ngIf="permission.isGranted('Pages.Administration.Anlasses.Delete')"
														(click)="deleteAnlass(record.anlass)">{{l('Delete')}}</a>
												</li>
                                                <li>
                                                    <a href="javascript:;" *ngIf="entityHistoryEnabled"
                                                       (click)="showHistory(record.anlass)">{{l('History')}}</a>
                                                </li>
                                            </ul>
                                        </div>
                                    </td>
                                    <td style="width:150px" pEditableColumn>
											<!--<span class="ui-column-title"> {{l('AnlassTyp')}}</span>
                                            {{record.anlass.anlassTyp}}
                                            -->
                                        <p-cellEditor>
                                            <ng-template pTemplate="input">
                                                <input pInputText type="text" [(ngModel)]="record.anlass.anlassTyp">
                                            </ng-template>
                                            <ng-template pTemplate="output">
                                                {{record.anlass.anlassTyp}}
                                            </ng-template>
                                        </p-cellEditor>
									</td>
                                </tr>
                            </ng-template>
                        </p-table>
						<div class="primeng-no-data" *ngIf="primengTableHelper.totalRecordsCount == 0">
                            {{l('NoData')}}
                        </div>
                        <div class="primeng-paging-container">
                            <p-paginator rows="{{primengTableHelper.defaultRecordsCountPerPage}}"
                                         #paginator
                                         (onPageChange)="getAnlasses($event)"
                                         [totalRecords]="primengTableHelper.totalRecordsCount"
                                         [rowsPerPageOptions]="primengTableHelper.predefinedRecordsCountPerPage">
                            </p-paginator>
                            <span class="total-records-count">
                                {{l('TotalRecordsCount', primengTableHelper.totalRecordsCount)}}
                            </span>
                        </div>
                    </div>
                    <!--<Primeng-Datatable-End>-->
                </div>
            </div>
        </div>
    </div>

    <createOrEditAnlassModal #createOrEditAnlassModal (modalSave)="getAnlasses()"></createOrEditAnlassModal>
    <viewAnlassModal #viewAnlassModal></viewAnlassModal>
     <entityTypeHistoryModal #entityTypeHistoryModal></entityTypeHistoryModal>
</div>

And the corresponding ts

import { Component, Injector, ViewEncapsulation, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { AnlassesServiceProxy, AnlassDto  } from '@shared/service-proxies/service-proxies';
import { NotifyService } from '@abp/notify/notify.service';
import { AppComponentBase } from '@shared/common/app-component-base';
import { TokenAuthServiceProxy } from '@shared/service-proxies/service-proxies';
import { CreateOrEditAnlassModalComponent } from './create-or-edit-anlass-modal.component';
import { ViewAnlassModalComponent } from './view-anlass-modal.component';
import { appModuleAnimation } from '@shared/animations/routerTransition';
import { Table } from 'primeng/components/table/table';
import { Paginator } from 'primeng/components/paginator/paginator';
import { LazyLoadEvent } from 'primeng/components/common/lazyloadevent';
import { FileDownloadService } from '@shared/utils/file-download.service';
import { EntityTypeHistoryModalComponent } from '@app/shared/common/entityHistory/entity-type-history-modal.component';
import * as _ from 'lodash';
import * as moment from 'moment';

@Component({
    templateUrl: './anlasses.component.html',
    encapsulation: ViewEncapsulation.None,
    animations: [appModuleAnimation()]
})
export class AnlassesComponent extends AppComponentBase {

    @ViewChild('createOrEditAnlassModal', { static: true }) createOrEditAnlassModal: CreateOrEditAnlassModalComponent;
    @ViewChild('viewAnlassModalComponent', { static: true }) viewAnlassModal: ViewAnlassModalComponent;
    @ViewChild('entityTypeHistoryModal', { static: true }) entityTypeHistoryModal: EntityTypeHistoryModalComponent;
    @ViewChild('dataTable', { static: true }) dataTable: Table;
    @ViewChild('paginator', { static: true }) paginator: Paginator;

    advancedFiltersAreShown = false;
    filterText = '';
    anlassTypFilter = '';


    _entityTypeFullName = 'namespacex.MerkmaleSports.Anlass';
    entityHistoryEnabled = false;

    constructor(
        injector: Injector,
        private _anlassesServiceProxy: AnlassesServiceProxy,
        private _notifyService: NotifyService,
        private _tokenAuth: TokenAuthServiceProxy,
        private _activatedRoute: ActivatedRoute,
        private _fileDownloadService: FileDownloadService
    ) {
        super(injector);
    }

    ngOnInit(): void {
        this.entityHistoryEnabled = this.setIsEntityHistoryEnabled();
    }

    private setIsEntityHistoryEnabled(): boolean {
        let customSettings = (abp as any).custom;
        return customSettings.EntityHistory && customSettings.EntityHistory.isEnabled && _.filter(customSettings.EntityHistory.enabledEntities, entityType => entityType === this._entityTypeFullName).length === 1;
    }

    getAnlasses(event?: LazyLoadEvent) {
        if (this.primengTableHelper.shouldResetPaging(event)) {
            this.paginator.changePage(0);
            return;
        }

        this.primengTableHelper.showLoadingIndicator();

        this._anlassesServiceProxy.getAll(
            this.filterText,
            this.anlassTypFilter,
            this.primengTableHelper.getSorting(this.dataTable),
            this.primengTableHelper.getSkipCount(this.paginator, event),
            this.primengTableHelper.getMaxResultCount(this.paginator, event)
        ).subscribe(result => {
            this.primengTableHelper.totalRecordsCount = result.totalCount;
            this.primengTableHelper.records = result.items;
            this.primengTableHelper.hideLoadingIndicator();
        });
    }

    reloadPage(): void {
        this.paginator.changePage(this.paginator.getPage());
    }

    createAnlass(): void {
        this.createOrEditAnlassModal.show();
    }

    showHistory(anlass: AnlassDto): void {
        this.entityTypeHistoryModal.show({
            entityId: anlass.id.toString(),
            entityTypeFullName: this._entityTypeFullName,
            entityTypeDescription: ''
        });
    }

    deleteAnlass(anlass: AnlassDto): void {
        this.message.confirm(
            '',
            (isConfirmed) => {
                if (isConfirmed) {
                    this._anlassesServiceProxy.delete(anlass.id)
                        .subscribe(() => {
                            this.reloadPage();
                            this.notify.success(this.l('SuccessfullyDeleted'));
                        });
                }
            }
        );
    }

    exportToExcel(): void {
        this._anlassesServiceProxy.getAnlassesToExcel(
        this.filterText,
            this.anlassTypFilter,
        )
        .subscribe(result => {
            this._fileDownloadService.downloadTempFile(result);
         });
    }
}

Thank you for your help.

Best, Tuna

Thank you @ryancyq and @ismcagdas for you support so far. We have decided to not follow up on the PhoneBook examle and are using the ApsNetZero Extension instead which is working fine. Thus we can close this issue.

This is my AddPhoneInput.cs

usingSystem.ComponentModel.DataAnnotations;

namespace rytlex.Persons.Dto
{
    public class AddPhoneInput
    {
        [Range(1, int.MaxValue)]
        public int PersonId { get; set; }

        [Required]
        public PhoneType Type { get; set; }

        [Required]
        [MaxLength(PhoneConsts.MaxNumberLength)]
        public string Number { get; set; }
    }
}

Hi,

I'm trying to implement the tutorial for the PhoneBook for AspNet Core & Angular (here) and am failing in the last step when trying to run the application.

I added the documented source code to both projects, Core & Angular. Core is building & executing fine. I also executed nswag. But somehow the both components AddPhoneInputType and PhoneInPersonListDtoType that are required by Angular's phonebook.component.ts file are missing in the service-proxies.ts. I noticed that they are also missing in the Swagger UI. So somehow they are not part of the API interface.

What am I missing?

Thanks, Tuna

Thank you for your quick response! That was indeed the issue! :D

Thanks! Disabling the filter seems to work to some extent. But I still have trouble with objects that contain foreign keys. For example:

This is the Request object:

public class Request : FullAuditedEntity, IMustHaveTenant
{
    ...

    [ForeignKey("RequestorId")]
    public virtual User Requestor { get; set; }
    public virtual long? RequestorId { get; set; }

    ...
}

This is the GetRequests service method:

public ListResultOutput<RequestListDto> GetRequests(GetRequestsInput input)
{
    using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MustHaveTenant))
    {
        var requests = _requestRepository
            .GetAll()
            .Include(p => p.Requestor)
            .WhereIf(
                !input.Filter.IsNullOrEmpty(),
                p =>
                    p.Requestor.UserName.Contains(input.Filter) ||
                    p.Requestor.Name.Contains(input.Filter) ||
                    p.Requestor.Surname.Contains(input.Filter) ||
                    p.Requestor.EmailAddress.Contains(input.Filter)
            )
            .OrderByDescending(p => p.CreationTime)
            .ToList();

        return new ListResultOutput<RequestListDto>(requests.MapTo<List<RequestListDto>>());
    }
}

Without disabling the filter, I didn't see any Request objects. Thanks to your suggestion and using the code above, I'm at least getting all the requests now from host. But the Requestor inside Request is null, probably because disabling the filter in the current unit of work doesn't apply there.

Do you have any suggestions or ideas on how to disable the filter in this case? Maybe somehow recursively or some kind of "always disable filter, if I am host". Thanks!

Hi again,

meanwhile I was able to set it up properly and now sending mails is working fine. I missed to remove check from default credentials and thus wasn't seeing the hidden fields.

For anyone who is interested in how to set it up:

  1. Goto E-Mail settings (see <a class="postlink" href="http://www.aspnetzero.com/Documents/Development-Guide#host-settings">http://www.aspnetzero.com/Documents/Dev ... t-settings</a>)
  2. First two fields are freely configurable
  3. Set STMP host to smtp.sendgrid.net (I left SMTP port & SSL unchanged)
  4. Uncheck "Use default credentials" and provide the username SendGrid has provided to you (it should be a long string with chars & ints), also provide the password you've set for SendGrid yourself

That should be it.

Regards, Tuna

Hi,

I wanted to ask if anyone has experiences setting up Asp.Net Zero with Azure & SendGrid? The default fields for setting up SMTP don't match to the configuration settings of SendGrid so I wonder how to get that work.

Thanks for your feedback, Regards, Tuna

Hi Halil Ibrahim,

in our project, where we are using the tenant/host distinction, we also have a use case of a call-center where the agents are expected to have a global access to all tenants' tickets in the system (imagine it as a kind of 'superview‘ if you like). No change for tenants, they will be able to create & edit their own data, namely tickets.

I'm not sure if this question was already covered in another topic or on GitHub (eventually issue #530 which seems to have similarity?) and wanted to ask for your advice on how to achieve this.

Generally I think that this feature would be very helpful in your Product (out-of-the-box).

Thank you very much in advance, Best regards, Tuna

Thanks! We had to update ABP though, because token-based authentication seems to be fairly new. ;) But it works great!

I think we may have found a bug. In AccountController.cs there was no LocalizationSourceName set. That's why we got this error, when it tried to throw a UserFriendlyException for an invalid username/password or other errors:

Abp.AbpException: Must set LocalizationSourceName before, in order to get LocalizationSource
Showing 1 to 10 of 11 entries