diff --git a/en/components/circular-progress.md b/en/components/circular-progress.md index edd216b511..80beec9c53 100644 --- a/en/components/circular-progress.md +++ b/en/components/circular-progress.md @@ -175,16 +175,16 @@ Add some styles: ### Gradient Progress -One way to customize the progress bar is to use a color gradient instead of a solid color. -This can be done in one of two ways - by using the [`IgxProgressBarGradientDirective`]({environment:angularApiUrl}/classes/igxcircularprogressbarcomponent.html#gradienttemplate) directive or by implementing a custom theme, albeit custom themes support up to two color stops. +One way to customize the progress bar is by using a color gradient instead of a solid color. +This can be done in one of two ways - by using the [`IgxProgressBarGradientDirective`]({environment:angularApiUrl}/classes/igxcircularprogressbarcomponent.html#gradienttemplate) directive or by implementing a custom theme, which supports up to two color stops. -If you want to create a gradient with just two color stops, you can do so by using a custom theme. Create a list of colors and pass it to the `$progress-circle-color` theme parameter: +To create a gradient with just two color stops using a custom theme, you need to create a list of colors and pass it to the `$fill-color-default` theme parameter: ```scss $colors: #695cf9, #ef017c; $custom-theme: progress-circular-theme( - $progress-circle-color: $colors, + $fill-color-default: $colors, ); ``` @@ -239,12 +239,12 @@ To get started with styling the circular progress bar, we need to import the `in // @import '~igniteui-angular/lib/core/styles/themes/index'; ``` -Following the simplest approach, we create a new theme that extends the [`progress-circular-theme`]({environment:sassApiUrl}/index.html#function-progress-circular-theme) and accepts the `$base-circle-color` and the `$progress-circle-color` parameters. +Following the simplest approach, we create a new theme that extends the [`progress-circular-theme`]({environment:sassApiUrl}/index.html#function-progress-circular-theme) and accepts the `$base-circle-color` and the `$fill-color-default` parameters. ```scss $custom-theme: progress-circular-theme( $base-circle-color: lightgray, - $progress-circle-color: rgb(32, 192, 17), + $fill-color-default: rgb(32, 192, 17), ); ``` diff --git a/en/components/grids_templates/advanced-filtering.md b/en/components/grids_templates/advanced-filtering.md index 223c7a913e..8652f6bc8c 100644 --- a/en/components/grids_templates/advanced-filtering.md +++ b/en/components/grids_templates/advanced-filtering.md @@ -80,8 +80,9 @@ To enable the advanced filtering, the [`allowAdvancedFiltering`]({environment:an ``` } -The advanced filtering generates a [`FilteringExpressionsTree`]({environment:angularApiUrl}/classes/filteringexpressionstree.html) which is stored in the [`advancedFilteringExpressionsTree`]({environment:angularApiUrl}/classes/@@igTypeDoc.html#advancedFilteringExpressionsTree) input property. You could use the [`advancedFilteringExpressionsTree`]({environment:angularApiUrl}/classes/@@igTypeDoc.html#advancedFilteringExpressionsTree) property to set an initial state of the advanced filtering. +The advanced filtering generates a [`FilteringExpressionsTree`]({environment:angularApiUrl}/classes/filteringexpressionstree.html) which is stored in the [`advancedFilteringExpressionsTree`]({environment:angularApiUrl}/classes/@@igTypeDoc.html#advancedFilteringExpressionsTree) input property. You could use this property to set an initial state of the advanced filtering. +@@if (igxName !== 'IgxHierarchicalGrid') { ```typescript ngAfterViewInit(): void { const tree = new FilteringExpressionsTree(FilteringLogic.And); @@ -109,6 +110,60 @@ ngAfterViewInit(): void { this.@@igObjectRef.advancedFilteringExpressionsTree = tree; } ``` +} + +@@if (igxName === 'IgxHierarchicalGrid') { +```TypeScript +ngAfterViewInit(): void { + const tree = new FilteringExpressionsTree(FilteringLogic.Or); + tree.filteringOperands.push({ + fieldName: 'Artist', + condition: IgxStringFilteringOperand.instance().condition('startsWith'), + conditionName: IgxStringFilteringOperand.instance().condition('startsWith').name, + searchVal: 'A' + }); + const subTree = new FilteringExpressionsTree(FilteringLogic.And); + subTree.filteringOperands.push({ + fieldName: 'GrammyAwards', + condition: IgxNumberFilteringOperand.instance().condition('greaterThanOrEqualTo'), + conditionName: IgxNumberFilteringOperand.instance().condition('greaterThanOrEqualTo').name, + searchVal: 1 + }); + subTree.filteringOperands.push({ + fieldName: 'Debut', + condition: IgxNumberFilteringOperand.instance().condition('lessThan'), + conditionName: IgxNumberFilteringOperand.instance().condition('lessThan').name, + searchVal: 2000 + }); + tree.filteringOperands.push(subTree); + this.@@igObjectRef.advancedFilteringExpressionsTree = tree; +} +``` + +The advanced filtering in the `IgxHierarchicalGrid` can be used to filter root grid data based on child grids data using the *IN / NOT-IN* operators. This way, subqueries can be created to define more complex filtering logic. More information about this functionality can be found in [`Query Builder's Using Sub-Queries section`](../query-builder-model.md#using-sub-queries). Here's a sample [`FilteringExpressionsTree`]({environment:angularApiUrl}/classes/filteringexpressionstree.html) with a subquery: + +```TypeScript +ngAfterViewInit(): void { + const albumsTree = new FilteringExpressionsTree(FilteringLogic.And, undefined, 'Albums', ['Artist']); + albumsTree.filteringOperands.push({ + fieldName: 'LaunchDate', + condition: IgxDateFilteringOperand.instance().condition('after'), + conditionName: IgxDateFilteringOperand.instance().condition('after').name, + searchVal: new Date(2017, 1, 1) + }); + const tree = new FilteringExpressionsTree(FilteringLogic.And); + tree.filteringOperands.push({ + fieldName: 'Artist', + condition: IgxStringFilteringOperand.instance().condition('inQuery'), + conditionName: IgxStringFilteringOperand.instance().condition('inQuery').name, + searchTree: albumsTree + }); + this.@@igObjectRef.advancedFilteringExpressionsTree = tree; +} +``` + +If remote data is used, the [`schema`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html#schema) property of the `IgxHierarchicalGrid` should be set. Please refer to [`Load on Demand`](../hierarchicalgrid/load-on-demand.md) topic for detailed guidance. +} In case you don't want to show the @@igComponent toolbar, you could use the [`openAdvancedFilteringDialog`]({environment:angularApiUrl}/classes/@@igTypeDoc.html#openAdvancedFilteringDialog) and [`closeAdvancedFilteringDialog`]({environment:angularApiUrl}/classes/@@igTypeDoc.html#closeAdvancedFilteringDialog) methods to open and close the advanced filtering dialog programmatically. @@ -167,7 +222,7 @@ It's super easy to configure the advanced filtering to work outside of the @@igC } @@if (igxName === 'IgxHierarchicalGrid') { ```html - + ``` } diff --git a/en/components/grids_templates/state-persistence.md b/en/components/grids_templates/state-persistence.md index ccde88d436..437d47e57d 100644 --- a/en/components/grids_templates/state-persistence.md +++ b/en/components/grids_templates/state-persistence.md @@ -115,6 +115,9 @@ _canonicalLink: grid/state-persistence > The [`IgxGridState`]({environment:angularApiUrl}/classes/igxgridstatedirective.html) directive does not take care of templates. Go to [Restoring Column](state-persistence.md#restoring-columns) section to see how to restore column templates. } +>[!NOTE] +> The `Row Selection` feature requires the [`primaryKey`]({environment:angularApiUrl}/classes/IgxGridComponent.html#primaryKey) property to be set, so it can be stored/restored correctly. + ## Usage [`getState`]({environment:angularApiUrl}/classes/igxgridstatedirective.html#getState) - This method returns the grid state in a serialized JSON string, so developers can just take it and save it on any data storage (database, cloud, browser localStorage, etc). The method accepts first optional parameter `serialize`, which determines whether [`getState`]({environment:angularApiUrl}/classes/igxgridstatedirective.html#getState) will return an [`IGridState`]({environment:angularApiUrl}/interfaces/igridstate.html) object or a serialized JSON string. diff --git a/en/components/hierarchicalgrid/load-on-demand.md b/en/components/hierarchicalgrid/load-on-demand.md index bbe8bae22e..2abdaa4535 100644 --- a/en/components/hierarchicalgrid/load-on-demand.md +++ b/en/components/hierarchicalgrid/load-on-demand.md @@ -8,13 +8,10 @@ _keywords: Ignite UI for Angular, UI controls, Angular widgets, web widgets, UI The Ignite UI for Angular [`IgxHierarchicalGrid`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html) allows fast rendering by requesting the minimum amount of data to be retrieved from the server so that the user can see the result in view and interact with the visible data as quickly as possible. Initially only the root grid’s data is retrieved and rendered, only after the user expands a row containing a child grid, he will receive the data for that particular child grid. This mechanism, also known as Load on Demand, can be easily configured to work with any remote data. - -This topic demonstrates how to configure Load on Demand by creating a Remote Service Provider that communicates with an already available remote oData v4 Service. Here's the working demo and later we will go through it step by step and describe the process of creating it. - +This topic demonstrates how to configure Load on Demand by requesting data from a [Northwind WebAPI](https://data-northwind.indigo.design/swagger/index.html). Here's the working demo and later we will go through it step by step and describe the process of creating it. ## Angular Hierarchical Grid Load On Demand Example - @@ -22,278 +19,195 @@ This topic demonstrates how to configure Load on Demand by creating a Remote Ser
-### Remote Service Provider - -First we will prepare our service provider so we will be ready to get the data we would need for the hierarchical grid. - -#### Getting basic data - -We will be communicating with our backend service over HTTP protocol using the XMLHttpRequest interface the browsers provide. In order to achieve this more easily we will use Angular's [`HttpClient`](https://angular.io/api/common/http/HttpClient) module that offers a simplified client HTTP API. That way in order to get our data we will need this simple method in our service: +### Hierarchical Grid Setup +Let's setup our hierarchical grid. First we will define our hierarchical grid template with the levels of hierarchy that we expect to have. We know that our root grid [`primaryKey`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html#primaryKey) for the customers is their `customerId`, for their orders on the first level - `orderId` and respectively for order details - `productId`. Knowing each database table and their keys allows us to define our initial template: -```typescript -public getData(dataState): Observable { - return this.http.get(this.buildUrl(dataState)).pipe( - map(response => response['value']), - ); -} +```html + + + + + + ``` -As you can see `this.http` will be a reference to our `HttpCLient` module, and `buildUrl()` will be the method that will generate our url based on the data that we have received. We map our response so we get only the value of our result and return an Observable, since this is executed asynchronously. That way we can later subscribe to it, process it further in our application and pass it to our grid. - -#### Building our request url - -Next we will define how we should build our URL for the GET request. This is where we will be able to get the data for our main grid but also for any child grid inside it. We will use the `Customers` data from [here](https://services.odata.org/V4/Northwind/Northwind.svc/) for our root level and use `Order` and `Order_Details` for the lower levels. The model will differ per application but we will use the following one: - - - - - What we first need is the `key` of our table to determine from where to get the data for the desired grid, the primary key of the parent row and its unique ID. We will define all this in an interface called `IDataState`. An example: - -```typescript -export interface IDataState { - key: string; - parentID: any; - parentKey: string; - rootLevel: boolean; -} +We will easily set the data of the root grid after getting its data from the endpoint in our code later, since we can use the `#hGrid` reference. Setting the data for any child that has been expanded is a bit different. -//... -public buildUrl(dataState: IDataState): string { - let qS = ""; - if (dataState) { - qS += `${dataState.key}?`; - - if (!dataState.rootLevel) { - if (typeof dataState.parentID === "string") { - qS += `$filter=${dataState.parentKey} eq '${dataState.parentID}'`; - } else { - qS += `$filter=${dataState.parentKey} eq ${dataState.parentID}`; - } - } - } - return `${this.url}${qS}`; -} -//... -``` +When a row is expanded for the first time, a new child `IgxHierarchicalGrid` is rendered for it and we need to get the reference for the newly created grid to set its data. That is why each [`IgxRowIsland`]({environment:angularApiUrl}/classes/igxrowislandcomponent.html) component provides the [`gridCreated`]({environment:angularApiUrl}/classes/igxrowislandcomponent.html#gridCreated) event that is fired when a new child grid is created for that specific row island. We can use that to get the reference we need for the new grid, request its data from the endpoint, and apply it. -#### Result +We can use one method for all row islands since the endpoint only needs the key of the row island, the primary key of the parent row, and its unique identifier. All this information can be accessed directly from the event arguments. -Finally, this is how our `remote-lod.service.ts` would look like: +#### Setup of loading indication +Now let's improve the user experience by informing the user that the data is still loading so he doesn't have to look at an empty grid in the meantime. That's why the [`IgxHierarchicalGrid`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html) supports a loading indicator that can be displayed while the grid is empty. -```typescript -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -export interface IDataState { - key: string; - parentID: any; - parentKey: string; - rootLevel: boolean; -} +We display a loading indicator by setting the [`isLoading`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html#isloading) property to `true` while there is no data. We need to set it initially for the root grid and also when creating new child grids, until their data is loaded. We could always set it to `true` in our template, but we want to hide it (by setting it to `false`) and display that the grid has no data if the service returns an empty array. -@Injectable() -export class RemoteLoDService { - url = `https://services.odata.org/V4/Northwind/Northwind.svc/`; +Finally, let's turn the [`autoGenerate`]({environment:angularApiUrl}/classes/igxgridcomponent.html#autoGenerate) property off and define the columns collection in the markup. - constructor(private http: HttpClient) { } +The template file `hierarchical-grid-lod.component.html`, after all changes added, would look like this: - public getData(dataState: IDataState): Observable { - return this.http.get(this.buildUrl(dataState)).pipe( - map((response) => response['value']) - ); - } +```html + + + + + + + + + + + + + + + + + + + + + + + +``` - public buildUrl(dataState: IDataState): string { - let qS = ""; - if (dataState) { - qS += `${dataState.key}?`; - - if (!dataState.rootLevel) { - if (typeof dataState.parentID === "string") { - qS += `$filter=${dataState.parentKey} eq '${dataState.parentID}'`; - } else { - qS += `$filter=${dataState.parentKey} eq ${dataState.parentID}`; - } +### Advanced filtering + +In order to use Advanced Filtering in the `IgxHierarchicalGrid` with load on demand, you need to set the [`schema`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html#schema) property of the grid to an entity with hierarchical structure, specifying child entities and fields with their data types. This ensures that filtering expressions with nested queries can be created even before any child grid data is loaded and that the grid can correctly interpret and apply these filters to the data. + +In our case, this is the correct hierarchical structure: + +```TypeScript +public schema: EntityType[] = [ + { + name: 'Customers', + fields: [ + { field: 'customerId', dataType: 'string' }, + { field: 'companyName', dataType: 'string' }, + { field: 'contactName', dataType: 'string' }, + { field: 'contactTitle', dataType: 'string' } + ], + childEntities: [ + { + name: 'Orders', + fields: [ + { field: 'customerId', dataType: 'string' }, + { field: 'orderId', dataType: 'number' }, + { field: 'employeeId', dataType: 'number' }, + { field: 'shipVia', dataType: 'string' }, + { field: 'freight', dataType: 'number' } + ], + childEntities: [ + { + name: 'Details', + fields: [ + { field: 'orderId', dataType: 'number' }, + { field: 'productId', dataType: 'number' }, + { field: 'unitPrice', dataType: 'number' }, + { field: 'quantity', dataType: 'number' }, + { field: 'discount', dataType: 'number' } + ] + } + ] } - } - return `${this.url}${qS}`; + ] } -} +]; ``` -### Hierarchical Grid Setup +#### Setting initial filter -Next we will setup our hierarchical grid and connect it to our remote service provider. +Now let's add initial filtering rules to our grid so that the root grid is filtered when first loaded. We will create a [`FilteringExpressionsTree`]({environment:angularApiUrl}/classes/filteringexpressionstree.html) and set it to the [`advancedFilteringExpressionsTree`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html#advancedFilteringExpressionsTree) property of the `IgxHierarchicalGrid` using the `ngOnInit` lifecycle hook. -#### Template defining +Let's say we want to filter customers that have order's freight at least `500`. We will take advantage of the ability to create nested queries in the filtering expressions and this is the result: -First we will define our hierarchical grid template with the levels of hierarchy that we expect to have. We know that our root grid [`primaryKey`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html#primaryKey) for the customers is their `CustomerID`, for their orders on the first level - `OrderID` and respectively for order details - `ProductID`. Knowing each database table and their keys allows us to define our initial template: +```TypeScript +public ngOnInit() { + const ordersTree = new FilteringExpressionsTree(FilteringLogic.And, undefined, 'Orders', ['customerId']); + ordersTree.filteringOperands.push({ + fieldName: 'freight', + ignoreCase: false, + condition: IgxNumberFilteringOperand.instance().condition('greaterThanOrEqualTo'), + conditionName: IgxNumberFilteringOperand.instance().condition('greaterThanOrEqualTo').name, + searchVal: '500' + }); -```html - - - - - - - - - - - - - - - - - - - - - + const customersTree = new FilteringExpressionsTree(FilteringLogic.And, undefined, 'Customers', ['customerId', 'companyName', 'contactName', 'contactTitle']); + customersTree.filteringOperands.push({ + fieldName: 'customerId', + condition: IgxStringFilteringOperand.instance().condition('inQuery'), + conditionName: IgxStringFilteringOperand.instance().condition('inQuery').name, + ignoreCase: false, + searchTree: ordersTree + }); + this.hGrid.advancedFilteringExpressionsTree = customersTree; +} ``` -There is one thing missing in our template though, and that is the data for our root level hierarchical grid, and eventually its children. We will easily set the data of the root grid after getting its data from the service in our code later, since we can use the `#hGrid` reference. Setting the data for any child that has been expanded is a bit different. - -When a row is expanded for the first time, a new child `IgxHierarchicalGrid` is rendered for it and we need to get the reference for the newly created grid to set its data. That is why each [`IgxRowIsland`]({environment:angularApiUrl}/classes/igxrowislandcomponent.html) component provides the [`gridCreated`]({environment:angularApiUrl}/classes/igxrowislandcomponent.html#gridCreated) event that is fired when a new child grid is created for that specific row island. We can use that to get the reference we need for the new grid, request its data from the service, and apply it. +### Connecting to the endpoint -We can use one method for all row islands since we built our service so that it needs only information if it is the root level, the key of the row island, the primary key of the parent row, and its unique identifier. All this information can be accessed either directly from the event arguments, or from the row island responsible for triggering the event. +We will be communicating with the endpoint over HTTP protocol using the XMLHttpRequest interface the browsers provide. In order to achieve this more easily we will use Angular's [`HttpClient`](https://angular.io/api/common/http/HttpClient) module that offers a simplified client HTTP API. -Let's name the method that we will use `gridCreated`. Since the event [`gridCreated`]({environment:angularApiUrl}/classes/igxrowislandcomponent.html#gridCreated) provides the [`parentID`]({environment:angularApiUrl}/interfaces/igridcreatedeventargs.html#parentID) property, a reference to the row island as [`owner`]({environment:angularApiUrl}/interfaces/igridcreatedeventargs.html#owner) and the new child [`grid`]({environment:angularApiUrl}/interfaces/igridcreatedeventargs.html#grid) property, it will be passed as the first argument. We are only missing information about the parent row's `primaryKey`, but we can easily pass that as a second argument, depending on which row island we bind. +#### Getting root grid data -The template file `hierarchical-grid-lod.component.html`, with these changes added, would look like this: +The [Northwind WebAPI](https://data-northwind.indigo.design/swagger/index.html) provides us with a POST endpoint that accepts an `IFilteringExpressionsTree` as a parameter and we will use it in order to take advantage of the Advanced Filtering functionality in the `IgxHierarchicalGrid` and filter records in the root grid. We will do this in `refreshRootGridData` method: -```html - - - - - - - - - - - - - - - - - - - - - +```typescript +public refreshRootGridData() { + const tree = this.hGrid.advancedFilteringExpressionsTree; + this.hGrid.isLoading = true; + if (tree) { + this.http.post(`${API_ENDPOINT}/QueryBuilder/ExecuteQuery`, tree).subscribe(data =>{ + this.remoteData = Object.values(data)[0]; + this.hGrid.isLoading = false; + this.hGrid.cdr.detectChanges(); + }); + } else { + this.http.get(`${API_ENDPOINT}/Customers`).subscribe(data => { + this.remoteData = Object.values(data); + this.hGrid.isLoading = false; + this.hGrid.cdr.detectChanges(); + }); + } +} ``` -#### Connecting our service +As you can see `this.http` will be a reference to our `HttpCLient` module. The `subscribe` method is part of Angular's Observable and is used to handle the asynchronous response from the HTTP request. When the data is received, it assigns the fetched data to the relevant grid, updates its loading state to false, and triggers change detection to ensure the UI reflects the changes. -One of our final steps now will be to connect our previously created service to our hierarchical grid. Since we defined it as an `Injectable`, we can pass it as a provider to our application. We will get a reference to our root grid as well, by using `ViewChild` query to set its data: - -````TypeScript -@Component({ - providers: [RemoteLoDService], - selector: "app-hierarchical-grid-lod", - styleUrls: ["./hierarchical-grid-lod.component.scss"], - templateUrl: "./hierarchical-grid-lod.component.html" -}) -export class HierarchicalGridLoDSampleComponent { - @ViewChild("hGrid") - public hGrid: IgxHierarchicalGridComponent; - - constructor(private remoteService: RemoteLoDService) { } -} -```` - -In order to make sure that out grid is rendered before we request its data from the service and assign it, we will use the `AfterViewInit` lifecycle hook. As it doesn't have any parents we can only pass that `rootLevel` is `true`, and the key for it, to the `getData` of our service. Since it returns an observable we will need to subscribe to it: +In order to load the data after the root grid is initially rendered, we will use the `ngAfterViewInit` lifecycle hook and call the `refreshRootGridData` method: ````TypeScript public ngAfterViewInit() { - this.remoteService.getData({ parentID: null, rootLevel: true, key: "Customers" }).subscribe((data) => { - this.hGrid.data = data; - this.hGrid.cdr.detectChanges(); - }); -} -```` - -Next, we only need to create our `gridCreated` method that will request data for any new child grid created. It will be similar to getting the root level grid data, just this time we will need to pass more information, like `parentID` and `parentKey`. `rootLevel` will be `false` for any child: - -````TypeScript -public gridCreated(event: IGridCreatedEventArgs, _parentKey: string) { - const dataState = { - key: event.owner.key, - parentID: event.parentID, - parentKey: _parentKey, - rootLevel: false - }; - this.remoteService.getData(dataState).subscribe( - (data) => { - event.grid.data = data; - event.grid.cdr.detectChanges(); - } - ); + this.refreshRootGridData(); } ```` -With this, the setup of our application is almost done. This last step aims to improve the user experience by informing the user that the data is still loading so he doesn't have to look at an empty grid in the meantime. That's why the [`IgxHierarchicalGrid`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html) supports a loading indicator that can be displayed while the grid is empty. If new data is received, the loading indicator will hide and the data will be rendered. +#### Getting child grids data -#### Setup of loading indication +Next we will define how we should build our URL for the GET request in order to get the data for our child grids. This is the visual representation of the relations between the tables: -The [`IgxHierarchicalGrid`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html) can display a loading indicator by setting the [`isLoading`]({environment:angularApiUrl}/classes/igxhierarchicalgridcomponent.html#isloading) property to `true` while there is no data. We need to set it initially for the root grid and also when creating new child grids, until their data is loaded. We could always set it to `true` in our template, but we want to hide it and display that the grid has no data if the service returns an empty array by setting it to `false`. + -In this case the final version of our `hierarchical-grid-lod.component.ts` would look like this: +Finally, we need to implement our `gridCreated` method that will request data for any new child grid created. It will be similar to getting the root level grid data, just this time we will use the data provided in the event [`gridCreated`]({environment:angularApiUrl}/classes/igxrowislandcomponent.html#gridCreated) and build our URL with it: ````TypeScript -import { AfterViewInit, Component, ViewChild } from "@angular/core"; -import { - IGridCreatedEventArgs, - IgxHierarchicalGridComponent, - IgxRowIslandComponent -} from "igniteui-angular"; -import { RemoteLoDService } from "../services/remote-lod.service"; - -@Component({ - providers: [RemoteLoDService], - selector: "app-hierarchical-grid-lod", - styleUrls: ["./hierarchical-grid-lod.component.scss"], - templateUrl: "./hierarchical-grid-lod.component.html" -}) -export class HierarchicalGridLoDSampleComponent implements AfterViewInit { - @ViewChild("hGrid") - public hGrid: IgxHierarchicalGridComponent; - - constructor(private remoteService: RemoteLoDService) { } - - public ngAfterViewInit() { - this.hGrid.isLoading = true; - this.remoteService.getData({ parentID: null, rootLevel: true, key: "Customers" }).subscribe((data) => { - this.hGrid.isLoading = false; - this.hGrid.data = data; - this.hGrid.cdr.detectChanges(); - }); - } +public gridCreated(event: IGridCreatedEventArgs) { + event.grid.isLoading = true; + const url = this.buildUrl(event); + this.http.get(url).subscribe(data => { + event.grid.data = Object.values(data); + event.grid.isLoading = false; + this.hGrid.cdr.detectChanges(); + }); +} - public gridCreated(event: IGridCreatedEventArgs, _parentKey: string) { - const dataState = { - key: event.owner.key, - parentID: event.parentID, - parentKey: _parentKey, - rootLevel: false - }; - event.grid.isLoading = true; - this.remoteService.getData(dataState).subscribe( - (data) => { - event.grid.isLoading = false; - event.grid.data = data; - event.grid.cdr.detectChanges(); - } - ); - } +private buildUrl(event: IGridCreatedEventArgs) { + const parentKey = (event.grid.parent as any).key ?? this.schema[0].name; + const url = `${API_ENDPOINT}/${parentKey}/${event.parentID}/${event.owner.key}`; + return url; } ```` diff --git a/en/components/themes/misc/angular-material-theming.md b/en/components/themes/misc/angular-material-theming.md index 6d91fa8a97..58b80d8406 100644 --- a/en/components/themes/misc/angular-material-theming.md +++ b/en/components/themes/misc/angular-material-theming.md @@ -101,7 +101,7 @@ To get started with styling components using the Ignite UI theming engine, creat ### Color Palettes -Ignite UI for Angular's [`igx-palette`]({environment:sassApiUrl}/index.html#function-igx-palette) function produces a color palette map including three sub-palettes for the `primary`, `secondary` and `gray` shades as well as five additional colors for `info`, `success`, `warn`, `error` and `surface`. For each color variant, our theming engine automatically generates text contrast colors at build-time, that are also included in the palette. Below, you can see the predefined light material palette: +Ignite UI for Angular's [`palette`]({environment:sassApiUrl}/index.html#function-igx-palette) function produces a color palette map including three sub-palettes for the `primary`, `secondary` and `gray` shades as well as five additional colors for `info`, `success`, `warn`, `error` and `surface`. For each color variant, our theming engine automatically generates text contrast colors at runtime, that are also included in the palette. Below, you can see the predefined light material palette: ```scss $igx-light-palette: palette( diff --git a/en/components/themes/palettes.md b/en/components/themes/palettes.md index 44cd907d26..6b4b68a936 100644 --- a/en/components/themes/palettes.md +++ b/en/components/themes/palettes.md @@ -45,7 +45,7 @@ As the table above shows, the `gray` color doesn't include the `A100`, `A200`, ` On top of the aforementioned colors, we also include **Level AA** [WCAG](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) compliant `contrast` colors for each color variant. This means that you can safely use the corresponding `contrast` color variants as foreground colors for the base color variant. > [!NOTE] -> Contrast colors are generated at build-time by the Sass theming engine based on the main variables color (primary, secondary, etc.). +> Contrast colors are CSS relative colors and are runtime calculated, based on the corresponding shade color (primary, secondary, etc.). Here's an excerpt of the `primary` variable color as declared in the Light Material Palette: @@ -53,25 +53,37 @@ Here's an excerpt of the `primary` variable color as declared in the Light Mater :root { //... --ig-primary-500: #09f; - --ig-primary-500-contrast: black; + --ig-primary-500-contrast: hsl(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l); --ig-primary-600: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-primary-600-contrast: black; + --ig-primary-600-contrast: hsl(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l); --ig-primary-700: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.81)); //... --ig-secondary-400: hsl(from var(--ig-secondary-500) h calc(s * 0.875) calc(l * 1.08)); - --ig-secondary-400-contrast: black; + --ig-secondary-400-contrast: hsl(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l); --ig-secondary-500: #df1b74; - --ig-secondary-500-contrast: white; + --ig-secondary-500-contrast: hsl(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l); --ig-secondary-600: hsl(from var(--ig-secondary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-secondary-600-contrast: white; + --ig-secondary-600-contrast: hsl(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l); //... + --ig-wcag-a: 0.31; + --ig-wcag-aa: 0.185; + --ig-wcag-aaa: 0.178; + --ig-contrast-level: var(--ig-wcag-aa); + --y: clamp(0,(y / var(--ig-contrast-level) - 1)* -infinity, 1); + --y-contrast: xyz-d65 var(--y) var(--y) var(--y); } ``` -All primary color variants are derived from one base variable color variant `--ig-primary-500`. The same goes for the other color variables `--ig-secondary-500`, `--ig-surface-500`, etc. The other variants are generated through the relative color function `hsl()` which takes the main variable color variant `500` and changes it's `staturation` and `lightness` according to the variable variant which is assigned on (`600`,`700`, etc.). We decided to use this approach as it allows us to modify all variants of the `primary`, `secondary`, `surface` and other colors at runtime. +All primary color variants come from a single base variable: `--ig-primary-500`. This same pattern applies to other color variables like `--ig-secondary-500` and `--ig-surface-500`. The additional variants are created using relative color CSS functions that take the main `500` variable and adjust its `saturation` and `lightness` to create other variants (600, 700, etc.). We chose this approach because it lets us modify all variants of `primary`, `secondary`, `surface`, and other colors during runtime. -> [!WARNING] -> Because the contrast colors are not generated at CSS runtime like the rest, if we change the main color variant(`500`), the contrast color would not be updated. We would need to change them manually. This behavior will be improved upon in an upcoming release, where the contrast colors will also be calculated at CSS runtime. + The contrast colors are CSS runtime generated, based on the the provided color's luminance and the chosen contrast-level to calculate the best contrast color for it. If we change the main color variant(`500`), the contrast colors will also be updated. + + > [!NOTE] + > You could specify the contrast-level globally by using the `palette` mixin, or if you'd like to set it specifically in the scope of your element, you could use the `adaptive-contrast` mixin. They both accept one of the predefined values: `a`, `aa` or `aaa`. + + ```scss + @include palette($palette, $contrast-level: 'aaa'); + ``` ## Defining Palettes diff --git a/en/components/toc.yml b/en/components/toc.yml index 2c2486eb62..55426b95b9 100644 --- a/en/components/toc.yml +++ b/en/components/toc.yml @@ -426,6 +426,7 @@ - name: Load on Demand href: hierarchicalgrid/load-on-demand.md new: false + updated: true - name: Editing href: hierarchicalgrid/editing.md new: false @@ -467,6 +468,7 @@ - name: Advanced Filtering href: hierarchicalgrid/advanced-filtering.md new: false + updated: true - name: Sorting href: hierarchicalgrid/sorting.md updated: false diff --git a/jp/components/circular-progress.md b/jp/components/circular-progress.md index c5a07be06c..8372d5af69 100644 --- a/jp/components/circular-progress.md +++ b/jp/components/circular-progress.md @@ -177,15 +177,15 @@ export class HomeComponent { ### グラデーション プログレス プログレス バーをカスタマイズする方法の 1 つとして、単色の代わりにカラー グラデーションを使用する方法があります。 -これは、[`IgxProgressBarGradientDirective`]({environment:angularApiUrl}/classes/igxcircularprogressbarcomponent.html#gradienttemplate) ディレクティブを使用する、もしくは、カスタムテーマを実装 することにより実行できます (カスタム テーマは 2 つまでの色経由点 (color stop) をサポートします)。 +これは、[`IgxProgressBarGradientDirective`]({environment:angularApiUrl}/classes/igxcircularprogressbarcomponent.html#gradienttemplate) ディレクティブを使用する、もしくは、カスタム テーマを実装することにより実行できます (カスタム テーマは 2 つまでの色経由点 (color stop) をサポートします)。 -2つの色経由点のみでグラデーションを作成する場合、カスタム テーマを使用できます。色のリストを作成し、それを `$progress-circle-color` テーマ パラメーターに渡します。 +カスタム テーマを使用して 2 つの色経由点のみを含むグラデーションを作成するには、色のリストを作成し、それを `$fill-color-default` テーマ パラメーターに渡す必要があります。 ```scss $colors: #695cf9, #ef017c; $custom-theme: progress-circular-theme( - $progress-circle-color: $colors, + $fill-color-default: $colors, ); ``` @@ -240,12 +240,12 @@ $custom-theme: progress-circular-theme( // @import '~igniteui-angular/lib/core/styles/themes/index'; ``` -最も簡単な方法として、[`progress-circular-theme`]({environment:sassApiUrl}/index.html#function-progress-circular-theme) を拡張し、`$base-circle-color` および `$progress-circle-color` パラメーターを受け取る新しいテーマを作成する方法があります。 +最も簡単な方法として、[`progress-circular-theme`]({environment:sassApiUrl}/index.html#function-progress-circular-theme) を拡張し、`$base-circle-color` および `$fill-color-default` パラメーターを受け取る新しいテーマを作成する方法があります。 ```scss $custom-theme: progress-circular-theme( $base-circle-color: lightgray, - $progress-circle-color: rgb(32, 192, 17), + $fill-color-default: rgb(32, 192, 17), ); ``` diff --git a/jp/components/grids_templates/state-persistence.md b/jp/components/grids_templates/state-persistence.md index 0944b63a0c..1c228bc04f 100644 --- a/jp/components/grids_templates/state-persistence.md +++ b/jp/components/grids_templates/state-persistence.md @@ -119,6 +119,9 @@ igxGridState ディレクティブによって開発者がグリッドの状態 > [`IgxGridState`]({environment:angularApiUrl}/classes/igxgridstatedirective.html) ディレクティブはテンプレートを処理しません。列テンプレートの復元方法については、「[列の復元](state-persistence.md#列の復元)」セクションを参照してください。 } +>[!NOTE] +> `Row Selection` 機能を使用するには、[`primaryKey`]({environment:angularApiUrl}/classes/IgxGridComponent.html#primaryKey) プロパティを設定して、正しく保存/復元する必要があります。 + ## 使用方法 [`getState`]({environment:angularApiUrl}/classes/igxgridstatedirective.html#getState) - このメソッドは、シリアル化された JSON 文字列でグリッド状態を返します。これは、開発者がそれを取得して任意のデータストレージ (データベース、クラウド、ブラウザーの localStorage など) に保存できます。このメソッドは最初のオプションのパラメーター `serialize` を受け取り、[`getState`]({environment:angularApiUrl}/classes/igxgridstatedirective.html#getState) が [`IGridState`]({environment:angularApiUrl}/interfaces/igridstate.html) オブジェクトを返すか、シリアル化された JSON 文字列を返すかを決定します。 diff --git a/jp/components/themes/misc/angular-material-theming.md b/jp/components/themes/misc/angular-material-theming.md index eb162aea97..072966236a 100644 --- a/jp/components/themes/misc/angular-material-theming.md +++ b/jp/components/themes/misc/angular-material-theming.md @@ -103,7 +103,7 @@ Ignite UI テーマ エンジンを使用してコンポーネントのスタイ ### カラー パレット -Ignite UI for Angular の [`palette`]({environment:sassApiUrl}/index.html#function-palette) 関数は、`primary`、`secondary`、`gray` 影の 3 つのサブパレットと、`info`、`success`、`warn`、`error` および `surface` の 5 つの追加カラーを含むカラー パレット マップを生成します。テーマ エンジンは、カラー バリエーションごとに、ビルド時にテキストのコントラスト カラーを自動的に生成します。これもパレットに含まれています。以下に、事前定義されたライト マテリアル パレットを示します: +Ignite UI for Angular の [`palette`]({environment:sassApiUrl}/index.html#function-palette) 関数は、`primary`、`secondary`、`gray` の 3 つのサブパレットと、`info`、`success`、`warn`、`error` および `surface` の 5 つの追加カラーを含むカラー パレット マップを生成します。テーマ エンジンは、カラー バリエーションごとに、実行時にテキストのコントラスト カラーを自動的に生成します。これもパレットに含まれています。以下に、事前定義されたライト マテリアル パレットを示します: ```scss $igx-light-palette: palette( diff --git a/jp/components/themes/palettes.md b/jp/components/themes/palettes.md index bb38464bd2..8f177109d8 100644 --- a/jp/components/themes/palettes.md +++ b/jp/components/themes/palettes.md @@ -46,7 +46,7 @@ Ignite UI for Angular は、`primary`、`secondary`、`surface`、`gray`、`info 上記のカラーに加えて、各カラー バリエーションに **Level AA** [WCAG](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html) 準拠の `contrast` カラーも含まれています。つまり、対応する `contrast` カラー バリエーションをベースカラー バリエーションの前景カラーとして安全に使用できます。 > [!NOTE] -> コントラスト カラーは、メイン変数のカラー (primary、secondary など) に基づいて、Sass テーマ設定エンジンによってビルド時に生成されます。 +> コントラスト カラーは CSS 相対カラーであり、対応するシェード カラー (primary、secondary など) に基づいて実行時に計算されます。 以下は、Light Material パレットで宣言された `primary` 変数カラーの抜粋です。 @@ -54,25 +54,37 @@ Ignite UI for Angular は、`primary`、`secondary`、`surface`、`gray`、`info :root { //... --ig-primary-500: #09f; - --ig-primary-500-contrast: black; + --ig-primary-500-contrast: hsl(from color(from var(--ig-primary-500) var(--y-contrast)) h 0 l); --ig-primary-600: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-primary-600-contrast: black; + --ig-primary-600-contrast: hsl(from color(from var(--ig-primary-600) var(--y-contrast)) h 0 l); --ig-primary-700: hsl(from var(--ig-primary-500) h calc(s * 1.26) calc(l * 0.81)); //... --ig-secondary-400: hsl(from var(--ig-secondary-500) h calc(s * 0.875) calc(l * 1.08)); - --ig-secondary-400-contrast: black; + --ig-secondary-400-contrast: hsl(from color(from var(--ig-secondary-400) var(--y-contrast)) h 0 l); --ig-secondary-500: #df1b74; - --ig-secondary-500-contrast: white; + --ig-secondary-500-contrast: hsl(from color(from var(--ig-secondary-500) var(--y-contrast)) h 0 l); --ig-secondary-600: hsl(from var(--ig-secondary-500) h calc(s * 1.26) calc(l * 0.89)); - --ig-secondary-600-contrast: white; + --ig-secondary-600-contrast: hsl(from color(from var(--ig-secondary-600) var(--y-contrast)) h 0 l); //... + --ig-wcag-a: 0.31; + --ig-wcag-aa: 0.185; + --ig-wcag-aaa: 0.178; + --ig-contrast-level: var(--ig-wcag-aa); + --y: clamp(0,(y / var(--ig-contrast-level) - 1)* -infinity, 1); + --y-contrast: xyz-d65 var(--y) var(--y) var(--y); } ``` -すべてのプライマリ カラー バリエーションは、1 つの基本変数カラー バリエーション `--ig-primary-500` から派生します。他のカラー変数 (`--ig-secondary-500`、`--ig-surface-500` など) にも同様のことが当てはまります。他のバリエーションは、メイン変数カラー バリエーション `500` を受け取り、割り当てられた変数バリエーション (`600`、`700` など) に応じて `saturation` と `lightness` を変更する相対カラー関数 `hsl()` によって生成されます。`primary`、`secondary`、`surface`、またはその他のカラーのすべてのバリエーションを実行時に変更できるため、この方法を使用することにしました。 +すべてのプライマリ カラー バリエーションは、単一の基本変数 (`--ig-primary-500`) から生成されます。同じパターンは、`--ig-secondary-500` や `--ig-surface-500` などの他のカラー変数にも適用されます。追加のバリエーションは、メインの `500` 変数を取得し、その `saturation` (彩度) と `lightness` (明度) を調整して他のバリエーション (600、700 など) を作成する、相対カラー CSS 関数を使用して作成されます。このアプローチを選んだ理由は、`primary`、`secondary`、`surface`、またはその他のカラーのすべてのバリエーションを実行時に変更できるようにするためです。 -> [!WARNING] -> コントラスト カラーは他の部分のように CSS 実行時に生成されないため、メイン カラー バリエーション (`500`) を変更しても、コントラスト カラーは更新されません。手動で変更する必要があります。この動作は今後のリリースで改善され、コントラスト カラーも CSS 実行時に計算されるようになります。 + コントラスト カラーは、指定されたカラーの輝度と選択されたコントラスト レベルに基づいて、 CSS ランタイムによって最適なコントラスト カラーが計算されます。メイン カラー バリエーション (`500`) を変更すると、コントラスト カラーも更新されます。 + + > [!NOTE] + > コントラスト レベルは、`palette` ミックスインを使用してグローバルに指定することも、特定の要素のスコープ内で `adaptive-contrast` ミックスインを使用して指定することもできます。どちらも、事前定義された値 `a`、`aa`、または `aaa` のいずれかを受け入れます。 + + ```scss + @include palette($palette, $contrast-level: 'aaa'); + ``` ## パレットの定義