I'm not a code ninja.. I've been using chatGPT to help me write some code for a model driven power app.
The code saves a form once all the required fields are filled in and should progress it to the next stage which is an approval cloud flow.
I attached this to a button using the ribbon workbench and the code saves the form but doesn't progress to the next stage and subsequently doesn't fire the cloud flow..
any help would be greatly appreciated!
function moveToNextStageAndRunWorkflow() {
// Get the ID of the record that you want to move to the next stage
var recordId = Xrm.Page.data.entity.getId();
// Get the entity name of the record that you want to move to the next stage
var entityName = Xrm.Page.data.entity.getEntityName();
// Save the form
Xrm.Page.data.entity.save().then(function () {
// Query for the next stage ID
Xrm.WebApi.retrieveRecord("processstage", "cea0b454-a3fe-4b10-881c-ede1f5d44ef6", "?$select=processid").then(function (result) {
var processId = result.processid;
// Move the record to the next stage
Xrm.WebApi.update({
entityName: entityName,
id: recordId,
data: {
stageid: "cea0b454-a3fe-4b10-881c-ede1f5d44ef6",
processid: "{D59CD510-F6A6-ED11-AAD1-6045BD0F9D4C}"
}
}).then(function (result) {
// Run the cloud workflow
Xrm.WebApi.online.execute({
entityName: "msdyn_workflow",
name: "ExecuteWorkflow",
parameter: {
"WorkflowId": "5de21d43-cb31-4fe0-a98b-371264369b80",
"EntityId": recordId
}
}).then(function (result) {
console.log("Workflow executed successfully.");
}).catch(function (error) {
console.error("Error executing workflow: " + error.message);
});
}).catch(function (error) {
console.error("Error moving record to the next stage: " + error.message);
});
}).catch(function (error) {
console.error("Error retrieving next stage ID: " + error.message);
});
}).catch(function (error) {
console.error("Error saving form: " + error.message);
});
}
I've been through lots of iterations and at first one was that I wasn't including the process id as well as the stage id but that still didn't fix the issue.
also I've since learnt that the code isn't to trigger a cloud flow, that needs to be done through a trigger in power automate, which it already is. but I'm trying to wrap it all into 1 swift motion. move it to the next stage and run the flow. all in the name of being user friendly.
Still stuck on this.. i've now tried using the out of the box functions that are already applied to buttons already within the ribbon, such as a simple save action by referencing the library and using XrmCore.Commands.Save.saveForm but to no avail!
Related
First of all, I have to say this is my first question on stack ;)
I am trying to implement a reading via NFC on my test web, but i dunno why, the ndefReader doesn't works on startup, i have to press any field on the web to get it loaded (or asked for permission).
BUT, if i wrote some alerts to check why it doen't reach the function on startup, it works!!! (of course, it show alerts before). I don't know if when I accept the alert, I am interacting with the web and that's why it works, but anyways, I dunno why this happens (I need to click anywhere before starting).
function iniciar() {
document.getElementById("input1").focus();
//alert("test before"); <--- IF i remove this, it doesnt works
document.getElementById("input1").addEventListener("blur", async () => {
try{
const ndef = new NDEFReader();
alert("before wait");
await ndef.scan();
alert("after wait");
ndef.addEventListener("readingerror", () => {
alert("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
alert(`> Serial Number: ${serialNumber}`);
alert(`> Records: (${message.records.length})`);
});
} catch (error) {
alert("Argh! " + error);
}
},false);
To scan and write to NFC tags, you must first request the "nfc" permission while handling a user gesture (e.g a button click, or in your case the "alert" call). Once handled, the NDEFReader scan() and write() methods trigger a user prompt, if access was not previously granted.
Check out https://web.dev/nfc/#security-and-permissions to learn more.
Hopefully https://googlechrome.github.io/samples/web-nfc/ samples should help you as well.
scanButton.addEventListener("click", async () => {
console.log("User clicked scan button");
try {
const ndef = new NDEFReader();
await ndef.scan();
console.log("> Scan started");
ndef.addEventListener("readingerror", () => {
console.log("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
console.log(`> Serial Number: ${serialNumber}`);
console.log(`> Records: (${message.records.length})`);
});
} catch (error) {
console.log("Argh! " + error);
}
});
My current ionic code able to get data then open the page. However, I want to open the page then only loading to get the data. I want to change the sequence since it takes 10s to load some data.
Here is my code:
$scope.openDetail = function (stock) {
console.log(stock.symbol);
$ionicLoading.show();
//stockCondition
if(stock.symbol.length<=$scope.stockCondition) {
$stockDataFactory.getStockDetails(stock).then(
function success(data) {
$globalFactory.personalStockData = data.details;
$globalFactory.personalStockNews = data.news;
$ionicLoading.hide();
$state.go("app.page1");
},
function error(error) {
alert(error.message);
console.error(error);
$ionicLoading.hide();
}
);
}
else{//WarrentCondition
$stockDataFactory.getWarrentDetails(stock).then(
function success(data) {
$globalFactory.personalStockData = data.details;
$globalFactory.personalStockNews = {};
$ionicLoading.hide();
$state.go("app.page1");
},
function error(error) {
alert("Stocks Not Found.");
console.error(error);
$ionicLoading.hide();
}
);
}
};//end
In order to open the $state.go("app.page1"); first, then only loading data, how shall I made changes of my code?
You should show the page1's html templet .
My approach will be using ng-if="personalStockData" with the $setTimeout() trick to show the data only when it's loaded. looks something like this
//page1 controller
$stockDataFactory.getStockDetails(stock).then(
function success(data) {
$setTimeout(function(){
$scope.personalStockData = data.details;
$scope.personalStockNews = data.news;
})
},
function error(error) {
alert(error.message);
console.error(error);
$ionicLoading.hide();
}
);
html
<div>
...
<div ng-if="personalStockData">
</div>
<div ng-if="personalStockNews">
</div>
...
</div>
anyways try not to use global variables, those are really hard to track.
You'll have to bring over the decision data that are explicit to the current page over to app.page1. For instance $scope.stockCondition. I suspect it is the same forstock.symbol. Will have to see what stock variable is.
There are many ways you can achieve this. Using query string is one option and is also the most conventional way. Some people prefer to store them in cookies, not efficient but applies to certain use-cases.
Again, I am not sure what $state is. Assuming it is angular-ui-router's statemanager. Then you can achieve this by;
$state.go("app.page1", {
stockCondition: $scope.stockCondition,
stocksymLen: stock.symbol.length
});
Then on app.page controller you can retrieve the values of the query string parameters by doing $state.params.stockCondition.
Once you have brought the decision variables across to the next page. The next step would be to plug them into the if-else statement you got from the other page onto app.page1.
Pseudo code:
angular.module('blah')
.controller('app.page1', function($scope, $state) {
// on page load
if($state.params.stocksymLen <= $state.params.stockCondition) {
// do your REST call
...
else {
...
}
});
I have an Word add-in (API 1.3) project where I can insert tables and make them content controls. I use the following code to recognize if the user clicks inside the table or selects any of its cells.
Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionChanged,
function() {
Word.run(function(ctx) {
var ctrl = ctx.document.getSelection().parentContentControl;
return ctx.sync()
.then(function() {
if (!ctrl.isNull) { // found - clicked inside the control
// ... load some properties, ...
ctrl.load('tag'); // How to get startRow, startCol, rowCount, colCount?
ctx.sync()
.then(function() {
console.log(ctrl.tag);
}).catch(function(err) {
console.log(err);
});
}
}).catch(function(err) {
console.log(err);
});
});
});
Is there a way to get the startRow, startCol, rowCount, colCount from here as in the binding event handlers for selectionChanged?
Thanks for sharing this question. 2 issues with your code:
You are subscribing to the document selection change, but you really want to do a Binding Selection Change. Note that coordinates are only returned on Table Bindings.
Once you have a table binding and subscribing to the right type of event, you need to add the event args on the handler to get access to the values you need.
Check out the following code to see how to create a table binding and also how to use the eventArgs on the handler to get the information you need (also note that you will get undefined on the rows acting as headers, if you have headers defined in the table):
Office.context.document.bindings.addFromSelectionAsync(Office.BindingType.Table, function (result) {
if (result.status == Office.AsyncResultStatus.Succeeded) {
// after creating the binding i am adding the handler for the BindingSelectionChanged, check out eventArgs usage....
var binding = result.value;
binding.addHandlerAsync(Office.EventType.BindingSelectionChanged, function (eventArgs) {
app.showNotification('Selection Coordinates: ' + eventArgs.startColumn + " " + eventArgs.columnCount + " " + eventArgs.startRow + " " + eventArgs.rowCount);
});
}
});
Hope this puts you in the right direction. thanks!
Juan.
I'm having a tough time getting push notifications (using the ngCordova plugin) to work. I have followed their sample code exactly as is documented on the site: http://ngcordova.com/docs/plugins/pushNotifications/
(the only difference is that I don't have a deviceready listener, instead, my code is inside the ionicPlatform.ready listener.)
Here is my code:
angular.module('myApp', ['ionic', 'ngCordova'])
.run(function($ionicPlatform, $rootScope, $state, $cordovaPush) {
$ionicPlatform.ready(function() {
var config = {
"senderID": "myID100001000"
};
$cordovaPush.register(config).then(function(result) {
alert(result);
}, function(err) {
alert(err);
})
});
$rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) {
switch(notification.event) {
case 'registered':
if (notification.regid.length > 0 ) {
alert('registration ID = ' + notification.regid);
}
break;
default:
alert('An unknown GCM event has occurred');
break;
}
});
})
When my app starts I do get the "OK" alert, so I know it successfully goes through the $cordovaPush.register call. However, I was expecting to get a "registered" notification event, right after, but I never get notified.
Any help would be appreciated.
The solution is in the comments but this needs a proper answer.
First of all, the register callback always returns OK as long as you pass a senderID, but if the $cordovaPush:notificationReceived event is never called (it may take a few seconds), this ID is probably wrong.
You must use the Project Number, not the Project ID.
To get the number, go to the API Console, select the project and you'll be on the Overview page. On top of this page, you'll see something like this:
Project ID: your-project-id Project Number: 0123456789
Just copy and use the project number and everything should work.
I have suffered with this a lot and I have found out, that there are in fact two versions of the cordova push plugin currently:
https://github.com/phonegap-build/PushPlugin (deprecated)
https://github.com/phonegap/phonegap-plugin-push (new one)
Both are supported by ngCordova, but only the deprecated version is documented.
The deprecated version is $cordovaPush
and the newer one is $cordovaPushV5, and they have completely different methods.
For me the problem was that I downloaded the cordova-plugin-push and tried to implement it with the old documentation on ngCordova site.
The code is:
/*
* Non deprecated version of Push notification events
*/
function registerV5() {
$ionicLoading.show({
template: '<ion-spinner></ion-spinner>'
});
if (ionic.Platform.is('browser')) {
alert("You are running on broswer, please switch to your device. Otherwise you won't get notifications");
$ionicLoading.hide();
return;
}
/**
* Configuration doc:
* https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/API.md#pushnotificationinitoptions
*/
var GCM_PROJECT_ID = 'xxxxxx';
$cordovaPushV5.initialize({
"android": {
"clearNotifications": false,
"senderID" : GCM_PROJECT_ID
}
});
$cordovaPushV5.register().then(function (deviceToken) {
console.log("Successfully registered", deviceToken);
$scope.data.deviceToken = deviceToken;
// Below code required to configure $cordovaPushV5 notifications emitter.
// Don't pass function it's not handler.
$cordovaPushV5.onNotification();
$cordovaPushV5.onError();
$ionicLoading.hide();
}, function (error) {
console.log("Failed to registered");
console.log("error object : ", error);
$ionicLoading.hide();
});
}
$rootScope.$on('$cordovaPushV5:notificationReceived', function(event, data) {
console.log("notification received");
console.log("data object: ", data);
var foreground = data.additionalData.foreground || false;
var threadID = data.additionalData.payload.threadID || '';
var group = data.additionalData.payload.group || false;
if (foreground) {
// Do something if the app is in foreground while receiving to push - handle in app push handling
console.log('Receive notification in foreground');
} else {
// Handle push messages while app is in background or not started
console.log('Receive notification in background');
// Open FB messanger app when user clicks notification UI when app is in background.
if (typeof data.additionalData.coldstart != "undefined" && data.additionalData.coldstart == false)
if (!group)
// Open FB Messenger of specific user chat window
window.open('fb-messenger://user/' + threadID, '_system', 'location=no');
else
// Open FB Messenger of specific group chat window
window.open('fb-messenger://groupthreadfbid/' + threadID, '_system', 'location=no');
}
});
$rootScope.$on('$cordovaPushV5:errorOccurred', function(event, error) {
console.log("notification error occured");
console.log("event object: ", event);
console.log("error object: ", error);
});
More on this github article: https://github.com/driftyco/ng-cordova/issues/1125 (code from here) and in this article: https://github.com/yafraorg/yafra/wiki/Blog-Ionic-PushV5
I am making a PM system, and I am currently adding the message starring system (so the user can star messages).
The problem is that if the user keeps starring and unstarring a message very fast (clicking it over and over again) it will mess up the server (the host will put a 503 error until the processes stop). To star a message it is simple as clicking the star to star it/clicking again to unstar it.
Is there a way to prevent it from being clicked a lot, or rather make an error pop up after it is clicked x number of times within a minute? That would prevent it from overloading the server because when you click the star it sends an AJAX request and updates the database; when you unstar it, it does the same thing.
Is there a jQuery way of showing an error if the star was clicked within a minute or so?
These are my functions for the starring:
function addStar(id) {
$('#starimg_' + id).removeClass("not_starred").addClass("starred");
$('#star_' + id).attr({
'title': 'Starred',
'onclick': 'removeStar(' + id + ')'
});
$.get('tools.php?type=addstar', {id: id}, function(data) {
if(data=='true') { // tools.php will echo 'true' if it is successful
alertBox('The message has been starred successfully', 2500);
}
else { alertBox('An error has occurred. Please try again later.'); }
});
}
function removeStar(id) {
$('#starimg_' + id).removeClass("starred").addClass("not_starred");
$('#star_' + id).attr({
'title': 'Not starred',
'onclick': 'addStar(' + id + ')'
});
$.get('tools.php?type=removestar', {id: id}, function(data) {
if(data=='true') { // tools.php will echo 'true' if it is successful
alertBox('The message has been unstarred successfully', 2500);
}
else { alertBox('An error has occurred. Please try again later.'); }
});
}
Thanks in advance!
here is a sample solution for your addStar function. This will send the request 2 sec after the users last click, so if the user is click happy those intermediate clicks will not send requests since the timer will be reset.
function addStar(id, delayRequests)
{
...
if(delayRequests == true){
clearTimeout(timer);
timer= setTimeout(function() { sendRequestToAddStar(id); },2000);
}
else{
sendRequestToAddStar(id);
}
}
function sendRequestToAddStar(id)
{
$.get('tools.php?type=removestar', {id: id}, function(data) {...
}
In any case, IMO it's better to not show an error message.
Consider starting/resetting a countdown timer every time the star is clicked. Once it counts down, send the current state of the star. User feedback is preserved and rate-limiting is honored.
They don't need to know there's a rate limit, or that it's not sending a request every time.
(That was a lot of words to describe a simple problem, and I think we know what "starring a message" means w/o a picture :)