Skip to content

Commit b76c0bc

Browse files
committed
Updating files
1 parent 489c406 commit b76c0bc

File tree

5 files changed

+197
-206
lines changed

5 files changed

+197
-206
lines changed

powerapps-docs/developer/component-framework/community-resources.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ The following is the list of blogs created by Power Apps community.
4141
- [Create code components](https://debajmecrm.com/2019/04/26/in-depth-end-end-walkthrough-develop-your-custom-controls-using-power-apps-component-framework-and-use-it-on-your-crm-interface/)
4242
- [Editing the DOM with supported code components](https://www.magnetismsolutions.com/blog/adammurchison/2019/05/29/editing-the-dom-with-supported-dynamics-365-custom-controls)
4343
- [How to configure Node.js and Typescript into your environment](https://capuanodanilo.com/2019/06/11/how-to-configure-node-js-and-typescript-into-your-environment-to-develop-powerapps-component-frameworks-pcf)
44+
- [Localization of code components](https://dynamicsninja.blog/2020/01/21/pcf-localization)
4445
- [Power Apps component framework – Frosting on the Cake](https://stevemordue.com/powerapps-component-framework-frosting-on-the-cake/)
4546
- [Public availability of Power Apps component framework – An important milestone](https://crmindian.com/2019/04/24/public-availability-of-powerapps-component-framework-an-important-milestone-for-powerapps-and-d365/)
4647
- [Work with code components using Power Apps component framework](https://powermaverick.dev/2019/05/18/create-custom-controls-using-powerapp-component-framework)
@@ -54,6 +55,7 @@ The following is the list of videos created by Power Apps community.
5455
- [Easier debugging with sourcemaps and Fiddler](https://www.youtube.com/watch?v=Ov-m5FBUj9g&feature=youtu.be)
5556
- [Getting started with code components](https://www.youtube.com/watch?v=ylhVZUlGgQw)
5657
- [Power Apps component framework Academy: Getting started](https://www.youtube.com/watch?v=YJ9hrKxAhTU)
58+
- [Power Apps component framework: Deep dive manifest file for dataset template](https://www.youtube.com/watch?v=TsTrYaOGaGo&feature=youtu.be)
5759
- [Power Apps component framework Academy: Deep dive manifest file for field template](https://www.youtube.com/watch?time_continue=522&v=w40zqSsYEy0)
5860
- [Power Apps component framework Academy: Dataset components](https://www.youtube.com/watch?v=OEiM97nTD0w)
5961
- [Power Apps component framework Academy: Importing into your organization](https://www.youtube.com/watch?v=2uO2L2xTPkc)

powerapps-docs/developer/component-framework/sample-controls/angular-flip-control.md

Lines changed: 182 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -54,200 +54,189 @@ The flip component sample consists of a label and a button. When you click on th
5454

5555
import { IInputs, IOutputs } from "./generated/ManifestTypes";
5656
import * as angular from "angular";
57-
export class JSAngularJSFlipControl
58-
implements ComponentFramework.StandardControl<IInputs, IOutputs> {
59-
// Element id of the ng-app div. Type: string
60-
private _appDivId: string;
61-
// ng-app app id. Type: string
62-
private _appId: string;
63-
// ng-controller. Type: string
64-
private _controllerId: string;
65-
// PCF framework delegate which will be assigned to this object which would be called whenever an update happens. Type: function
66-
private _notifyOutputChanged: () => void;
67-
// Model of the bind field. Type: Boolean
68-
private _currentValue: boolean;
69-
// Option Label Text when Option is True. The Text is from attribute customization. Type: string
70-
private _optionTrueLabel: string;
71-
// Option Label Text when Option is False. The Text is from attribute customization. Type: string
72-
private _optionFalseLabel: string;
73-
/**
74-
* Empty constructor.
75-
*/
76-
constructor() {}
77-
/**
78-
* Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
79-
* Data-set values are not initialized here, use updateView.
80-
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.
81-
* @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.
82-
* @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.
83-
* @param container If control is marked control-type='standard', it receives an empty div element within which it can render its content.
84-
*/
85-
public init(
86-
context: ComponentFramework.Context<IInputs>,
87-
notifyOutputChanged: () => void,
88-
state: ComponentFramework.Dictionary,
89-
container: HTMLDivElement
90-
) {
91-
// We need a random integer from 1-100, so that for a form of multiple fields bind to same attribute, we could differentiate
92-
let randomInt: number = Math.floor(Math.floor(100) * Math.random());
93-
let _this = this;
94-
this._appDivId = this.createUniqueId(
95-
context,
96-
"angularflip_controlid",
97-
randomInt
98-
);
99-
this._appId = this.createUniqueId(
100-
context,
101-
"JSAngularJSFlipControl",
102-
randomInt
103-
);
104-
this._controllerId = this.createUniqueId(
105-
context,
106-
"powerApps.angularui.demo",
107-
randomInt
108-
);
109-
this._notifyOutputChanged = notifyOutputChanged;
110-
// Assign Model the value of the bind attribute
111-
this._currentValue = context.parameters.flipModel.raw;
112-
// Initialize the True/False Label texts from the attribute metadata
113-
this.initializeOptionsLabel(context);
114-
// Create HTML structure for the control
115-
let appDiv: HTMLDivElement = document.createElement("div");
116-
appDiv.setAttribute("id", this._appDivId);
117-
appDiv.setAttribute("ng-controller", this._appId);
118-
appDiv.setAttribute("ng-app", this._controllerId);
119-
// Below sample html are from Angular-UI single toggle sample code
120-
// https://angular-ui.github.io/bootstrap/
121-
appDiv.innerHTML =
122-
"<pre>{{labelModel}}</pre><button type='button' class='btn btn-primary' ng-model='flipButtonModel' uib-btn-checkbox btn-checkbox-true='1' btn-checkbox-false='0'>Flip</button>";
123-
// Container appends the HTML structure
124-
container.appendChild(appDiv);
125-
// Angular code. Angular module/controller initialization.
126-
angular.module(this._controllerId, [
127-
"ngAnimate",
128-
"ngSanitize",
129-
"ui.bootstrap"
130-
]);
131-
angular.module(this._controllerId).controller(this._appId, $scope => {
132-
// Intialize 'labelModel'. Assign initial option text to the Angular $scope labelModel. It will be revealed in '<pre>{{labelModel}}</pre>'
133-
$scope.labelModel = _this._currentValue
134-
? _this._optionTrueLabel
135-
: _this._optionFalseLabel;
136-
// Intialize 'flipButtonModel'. Assign bind attribute value to Angular $scope flipButtonModel. The Flip button also bind to this 'flipButtonModel', so when we click, it will flip
137-
$scope.flipButtonModel = _this._currentValue ? 1 : 0;
138-
// Watch the click of the flip button
139-
$scope.$watchCollection("flipButtonModel", () => {
140-
// Update the label text when Flip Button clicks
141-
if ($scope.flipButtonModel) {
142-
$scope.labelModel = _this._optionTrueLabel;
143-
} else {
144-
$scope.labelModel = _this._optionFalseLabel;
145-
}
146-
// Call updateOutputIfNeeded and inform PCF framework that bind attribute value need update
147-
_this.updateOutputIfNeeded($scope.flipButtonModel);
148-
});
149-
});
150-
// Angular code. Create an App based on the new appDivId
151-
angular.element(document).ready(() => {
152-
angular.bootstrap(document.getElementById(_this._appDivId)!, [
153-
_this._controllerId
154-
]);
155-
});
156-
}
157-
/**
158-
* Get UniqueId so as to avoid id conflict between multiple fields bind to same attribute
159-
* @param context The "Input Properties" containing the parameters, control metadata and interface functions.
160-
* @param passInString input string as suffix
161-
* @param randomInt random integer
162-
* @returns a string of uniqueId includes attribute logicalname + passIn specialized string + random Integer
163-
*/
164-
private createUniqueId(
165-
context: ComponentFramework.Context<IInputs>,
166-
passInString: string,
167-
randomInt: number
168-
): string {
169-
return (
170-
context.parameters!.flipModel.attributes!.LogicalName +
171-
"-" +
172-
passInString +
173-
randomInt
174-
);
175-
}
176-
/**
177-
* Initialize Options Label to use the attribute label from Metadata
178-
* @param context The "Input Properties" containing the parameters, control metadata and interface functions.
179-
*/
180-
private initializeOptionsLabel(
181-
context: ComponentFramework.Context<IInputs>
182-
): void {
183-
var _this = this;
184-
// Get option label texts from metadata
185-
var optionsMetadata = context.parameters.flipModel.attributes!.Options;
186-
optionsMetadata.forEach((option: any) => {
187-
if (option.Value) {
188-
_this._optionTrueLabel = option.Label;
189-
} else {
190-
_this._optionFalseLabel = option.Label;
191-
}
192-
});
193-
}
194-
/**
195-
* Update Angular 'flipButtonModel' if needed
196-
* @param newValue new value
197-
*/
198-
private updateFlipButtonModelIfNeeded(newValue: boolean): void {
199-
if (
200-
(newValue && !this._currentValue) ||
201-
(!newValue && this._currentValue)
202-
) {
203-
this._currentValue = newValue;
204-
// Angular Code. Update the 'flipButtonModel' value
205-
var $scope = angular
206-
.element(document.getElementById(this._appDivId)!)
207-
.scope();
208-
$scope.$apply(($scope: any) => {
209-
// 'flipButtonModel' value is either 1 or 0
210-
$scope.flipButtonModel = newValue ? 1 : 0;
211-
});
212-
}
213-
}
214-
/**
215-
* Update value in Power Apps component framework
216-
* @param newValue new value
217-
*/
218-
private updateOutputIfNeeded(newValue: boolean): void {
219-
if (
220-
(newValue && !this._currentValue) ||
221-
(!newValue && this._currentValue)
222-
) {
223-
this._currentValue = newValue ? true : false;
224-
this._notifyOutputChanged();
225-
}
226-
}
227-
/**
228-
* Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.
229-
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions
230-
*/
231-
public updateView(context: ComponentFramework.Context<IInputs>): void {
232-
// An attribute value from Control Framework could be updated even after init cycle, clientAPI, post Save response can update the attribute value and the Flip control should reveal the new value.
233-
this.updateFlipButtonModelIfNeeded(context.parameters.flipModel.raw);
234-
}
235-
/**
236-
* It is called by the framework prior to a control receiving new data.
237-
* @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output”
238-
*/
239-
public getOutputs(): IOutputs {
240-
var returnValue = this._currentValue;
241-
return { flipModel: returnValue };
242-
}
243-
/**
244-
* Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.
245-
* i.e. canceling any pending remote calls, removing listeners, etc.
246-
*/
247-
public destroy(): void {
248-
// Add code to cleanup control if necessary
249-
}
57+
import * as ngAnimate from "angular-animate";
58+
import * as ngSanitize from "angular-sanitize";
59+
import * as uiBootstrap from "angular-ui-bootstrap";
60+
export class JSAngularJSFlipControl implements ComponentFramework.StandardControl<IInputs, IOutputs> {
61+
62+
// Element id of the ng-app div. Type: string
63+
private _appDivId: string;
64+
// ng-app app id. Type: string
65+
private _appId: string;
66+
// ng-controller. Type: string
67+
private _controllerId: string;
68+
// PCF framework delegate which will be assigned to this object which would be called whenever any update happens. Type: function
69+
private _notifyOutputChanged: () => void;
70+
// Model of the bind field. Type: Boolean
71+
private _currentValue: boolean;
72+
// Option Label Text when Option is True. The Text is from attribute customization. Type: string
73+
private _optionTrueLabel: string;
74+
// Option Label Text when Option is False. The Text is from attribute customization. Type: string
75+
private _optionFalseLabel: string;
76+
77+
/**
78+
* Empty constructor.
79+
*/
80+
constructor() {
81+
82+
}
83+
84+
/**
85+
* Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
86+
* Data-set values are not initialized here, use updateView.
87+
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.
88+
* @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.
89+
* @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.
90+
* @param container If a control is marked control-type='standard', it will receive an empty div element within which it can render its content.
91+
*/
92+
public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container: HTMLDivElement) {
93+
// We need a random integer from 1-100, so that for a form of multiple fields bind to same attribute, we could differentiate
94+
let randomInt: number = Math.floor(Math.floor(100) * Math.random());
95+
let _this = this;
96+
97+
this._appDivId = this.createUniqueId(context, "angularflip_controlid", randomInt);
98+
this._appId = this.createUniqueId(context, "JSAngularJSFlipControl", randomInt);
99+
this._controllerId = this.createUniqueId(context, "powerApps.angularui.demo", randomInt);
100+
this._notifyOutputChanged = notifyOutputChanged;
101+
102+
// Assign Model the value of the bind attribute
103+
this._currentValue = context.parameters.flipModel.raw;
104+
105+
// Initialize the True/False Label texts from the attribute metadata
106+
this.initializeOptionsLabel(context);
107+
108+
// Create HTML structure for the control
109+
let appDiv: HTMLDivElement = document.createElement('div');
110+
appDiv.setAttribute("id", this._appDivId);
111+
appDiv.setAttribute("ng-controller", this._appId);
112+
appDiv.setAttribute("ng-app", this._controllerId);
113+
114+
// Below sample html are from Angular-UI single toggle sample code
115+
// https://angular-ui.github.io/bootstrap/
116+
appDiv.innerHTML = "<pre>{{labelModel}}</pre><button type='button' class='btn btn-primary' ng-model='flipButtonModel' uib-btn-checkbox btn-checkbox-true='1' btn-checkbox-false='0'>Flip</button>";
117+
118+
// Container appends the HTML structure
119+
container.appendChild(appDiv);
120+
121+
// Angular code. Angular module/controller initialization.
122+
angular.module(this._controllerId, [require('angular-animate'), require('angular-sanitize'), require('angular-ui-bootstrap')]);
123+
angular.module(this._controllerId).controller(this._appId, ($scope) => {
124+
125+
// Intialize 'labelModel'. Assign initial option text to the Angular $scope labelModel. It will be revealed in '<pre>{{labelModel}}</pre>'
126+
$scope.labelModel = _this._currentValue ? _this._optionTrueLabel : _this._optionFalseLabel;
127+
128+
// Intialize 'flipButtonModel'. Assign bind attribute value to Angular $scope flipButtonModel. The Flip button also bind to this 'flipButtonModel', so when we click, it will flip
129+
$scope.flipButtonModel = _this._currentValue ? 1 : 0;
130+
131+
// Watch the click of the flip button
132+
$scope.$watchCollection('flipButtonModel', () => {
133+
134+
// Update the label text when Flip Button clicks
135+
if ($scope.flipButtonModel) {
136+
$scope.labelModel = _this._optionTrueLabel;
137+
}
138+
else {
139+
$scope.labelModel = _this._optionFalseLabel;
140+
}
141+
142+
// Call updateOutputIfNeeded and inform PCF framework that bind attribute value need update
143+
_this.updateOutputIfNeeded($scope.flipButtonModel);
144+
145+
});
146+
});
147+
148+
// Angular code. Create an App based on the new appDivId
149+
angular.element(document).ready(() => {
150+
angular.bootstrap(document.getElementById(_this._appDivId)!, [_this._controllerId]);
151+
});
250152
}
153+
154+
/**
155+
* Get UniqueId so as to avoid id conflict between multiple fields bind to same attribute
156+
* @param context The "Input Properties" containing the parameters, control metadata and interface functions.
157+
* @param passInString input string as suffix
158+
* @param randomInt random integer
159+
* @returns a string of uniqueId includes attribute logicalname + passIn specialized string + random Integer
160+
*/
161+
private createUniqueId(context: ComponentFramework.Context<IInputs>, passInString: string, randomInt: number): string {
162+
return context.parameters!.flipModel.attributes!.LogicalName + "-" + passInString + randomInt;
163+
}
164+
165+
/**
166+
* Initialize Options Label to use the attribute label from Metadata
167+
* @param context The "Input Properties" containing the parameters, control metadata and interface functions.
168+
*/
169+
private initializeOptionsLabel(context: ComponentFramework.Context<IInputs>): void {
170+
var _this = this;
171+
172+
// Get option label texts from metadata
173+
var optionsMetadata = context.parameters.flipModel.attributes!.Options;
174+
optionsMetadata.forEach((option: any) => {
175+
if (option.Value) {
176+
_this._optionTrueLabel = option.Label;
177+
}
178+
else {
179+
_this._optionFalseLabel = option.Label;
180+
}
181+
})
182+
}
183+
184+
/**
185+
* Update Angular 'flipButtonModel' if needed
186+
* @param newValue new value
187+
*/
188+
private updateFlipButtonModelIfNeeded(newValue: boolean): void {
189+
if ((newValue && !this._currentValue) || (!newValue && this._currentValue)) {
190+
this._currentValue = newValue;
191+
192+
// Angular Code. Update the 'flipButtonModel' value
193+
var $scope = angular.element(document.getElementById(this._appDivId)!).scope();
194+
195+
$scope.$apply(($scope: any) => {
196+
// 'flipButtonModel' value is either 1 or 0
197+
$scope.flipButtonModel = newValue ? 1 : 0;
198+
});
199+
}
200+
}
201+
202+
/**
203+
* Update value in Power Control Framework
204+
* @param newValue new value
205+
*/
206+
private updateOutputIfNeeded(newValue: boolean): void {
207+
if ((newValue && !this._currentValue) || (!newValue && this._currentValue)) {
208+
this._currentValue = newValue ? true : false;
209+
this._notifyOutputChanged();
210+
}
211+
}
212+
213+
/**
214+
* Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.
215+
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions
216+
*/
217+
public updateView(context: ComponentFramework.Context<IInputs>): void {
218+
// An attribute value from Control Framework could be updated even after init cycle, clientAPI, post Save response can update the attribute value and the Flip control should reveal the new value.
219+
this.updateFlipButtonModelIfNeeded(context.parameters.flipModel.raw);
220+
}
221+
222+
223+
/**
224+
* It is called by the framework prior to a control receiving new data.
225+
* @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output”
226+
*/
227+
public getOutputs(): IOutputs {
228+
var returnValue = this._currentValue;
229+
return { flipModel: returnValue };
230+
}
231+
232+
/**
233+
* Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.
234+
* i.e. cancelling any pending remote calls, removing listeners, etc.
235+
*/
236+
public destroy(): void {
237+
// Add code to cleanup control if necessary
238+
}
239+
251240
```
252241
253242
### Resources

0 commit comments

Comments
 (0)