Hi friends, it's Scott Durow. Welcome to another episode
of Power Apps Cafe. In this episode, we are gonna be
looking at five ways of running a cloud flow from a grid of
records inside a model driven app. So if that's something that
interests you, stick around. Well, there are broadly two ways of
running flows from model driven apps. Now, the first is having a single
flow that can be run for each record that you've selected. So that will, if you have 10
records selected, that will run 10 versions of that flow. Another option is to have a single flow
that accepts a list of records in this case 10 records, and then runs a action
inside, a a loop for those 10 records. Both are equally valid and may
suit different scenarios, so let's start with the first option. Okay. So there has been a button that
says Flow inside model driven apps for a very, very long time. And it's been one of these things
that really hasn't had very much attention for a very long time. So I talk about it as
the legacy flow button. And the way that this works is
that you have a model driven app. And you have a grid and there's
a flow button, and you can create a flow from that grid. And what that does is it allows you
to run that flow from that grid and uses the Dataverse Legacy connector. And it's a special trigger
called when a record is selected. We don't currently have the
same trigger inside the current in the new data connector. Also you can't add these
flows to a solution because of using that legacy trigger. So it, I kind of think about
them more as a personal flow, as a personal productivity flow. So if we come into our milestone app,
Milestone Manager app that we've been looking at over this series of videos,
If we go into the projects grid and we wanted to have a flow that we can run
on each of these individual projects that we've selected, and we go over
to the command bar at the top here. There is a option here for flow. And this is where this, this
button here has been for a very, here for a very long time. So we've got two options. We've got create a Flow
and see your flows. So you can see right from
the beginning it's very much about your own personal flows. I'm gonna create a flow and we can
see straight away that it's using the legacy Microsoft Dataverse trigger. And so I'm gonna continue and
that's gonna go and create it. And we are creating it
inside Power Automate. So it's outside of a solution and you
can see it populates by using the default environment and the projects table. And then I can start to add steps,
you know, all the things that we would like to do in, you know,
maybe, I don't know, create an email, send an email via Office 365. And once we've done that, that
will then appear in our lists of flows inside our model driven app. Let me just create one quickly as a
dummy one, and I'm just gonna save this and, and it's actually just
named it Microsoft Dataverse button. But you could obviously rename it. Now, if I go into back into
my model driven app, I'm gonna obviously have to refresh this. And now when we go over to the
flows, you can see here there's our Microsoft dataverse button,
and that's only gonna show for me. So I'm not gonna talk about that anymore. Personal productivity flow, you can
use it for on, on a per user basis. The next option is where you've
got a grid in a model driven app, you can use , the bulk edit option
to trigger a flow by defining your flow to run on update of a record. So we could create a, it could be a dummy
attribute or it could be an attribute that's already there and edit it in
using the standard edit functionality. And then when that attribute is changed
in the flow, we will then filter only to trigger when the attribute
has changed, and so we can then run functionality for each of those records. So I'm gonna create a new flow here
and I'm gonna use the automated flow because we want to make sure that this
triggers on when we update our project record, because the idea is that we
are going to trigger a flow when the project status attribute is updated
because I create this dummy attribute. And the idea is we use bulk edit to
update that particular attribute. And then for every single project
that has that attribute updated, it will then go and trigger this flow. So we might want to make sure that we use
the dataverse connector and there are two. There is a, when row is added, modified,
or deleted, Microsoft Dataverse, but there's also down the bottom
here, there is when row modified, and this is actually the legacy
connector, so don't wanna use that. So I'll, I'll create this. And so the change type we want to
have when it's modified, and that's, that's the, the filter we're using. And we we're gonna say when projects
are modified, and we're gonna say, Well, this is gonna run for every
single person that's up updating this. I'm gonna select the advance options
here, and I'm gonna start to trigger this only on particular columns. So I only want to trigger this when the
report generation status is updated. And I also want to provide an additional
trigger here to say when the report generation status is starts with trigger. And then the next, let's just create
a, a dummy step like we did before. So let's put a composing and just put the,
let's put the ID of our project which is going to be, Let's zoom out here about,
so we're getting a different one here. Let's get the project id. There we go. And then we'll save that. We're also gonna add in another step
here to say the Microsoft Dataverse connector here, which we're gonna
update, update a row because once it's been triggered, we'll go and create the
report, which will all, that will be all of the bits in between these two steps
here, which we're emitting just cause we're not gonna do that in this video. And we're gonna say, we're gonna update
the project that was triggered on this and we're going to go and clear out
that project report generation status. So I'm gonna say it's completed like that. So that once it's finished we know it's
actually has actually done its work. So I'll save that away. So let's test this. Now if we come into the set of
projects here, I can now use this edit, bulk edit function. I mean, if, if you select this and
you've only got a single record selected, it's just gonna open that
individual records on a standard form. But the great thing is now if we
select edit here, we now get this dialogue that allows us to edit bulk
records, which is very, very cool. So if I come into admin, I've actually got
my project generation status field here. So I can go in and select, I can just
type in trigger, and if I select that like that, and you can see it updated
all of those individual records. And so here we go. All of these records have got that
set to trigger one, and if I refresh this, you'll see that gradually. Oh, okay. There we go. That was very quick. They're now all completed. So that's a, a pretty easy
way of triggering your flows. Very low effort. Obviously it's a little bit cumbersome
because the user has to know which attribute to update to trigger the flow. So the next option is to
use a power Fx button. So if we have the same scenario,
we have a grid of projects, what we can do is you can use the new
commanding feature to add a button. And then we can put some power
effects that to actually patch that same attribute that we manually
updated using the bulk edit. And of course, that would
have the same result. It would then trigger the flow. So let's look at doing that. So here I'm in my App designer which is
for the, for the Milestone Manager app. And I'm going to go to the project
table that I've added in here, and I'm going to use Edit Command bar on
the, the Ellipses menu of project. So, and that, what that does is opens
up my command editor, so allows me to add buttons and I'm going to select
the the main grid of my project. So if I go, actually, let's use, let's
use the subgrid so we can do this underneath a particular account and
run it for a selected account projects. So this is showing at the top here. You can see this is the
Subgrid view for project. I can come in here and now I can
go and create a new command and I can call this generate reports. And let's call it in Power Fx in brackets. Why not? Let's use it, give it an icon. What should we give it? Let's give it that icon and I'm going
to select to use open the formula bar. Cause I wanna run a Power FX formula here. So what that gives me is at the,
the top here is it gives me on select, which is the event that
happens when I click my my button. So there, I'm gonna pop in a bit of. Power Fx into this. And if we look at how this
works, what this gives us is a. It gives us the patch statement. So we're gonna patch all of the projects
that are selected in the current grid. Now, there is is an interesting thing
here because what we're doing here is we are not going for all selected items
and then patching each of the items. What we're doing here is we are patching. The projects and we're passing that in a
collection of updated items because what that means that it will do it, it will
do them an in parallel to each other. If we put the ForAll around each of the
patches, it will basically do a patch for each of the selected items in a sequence,
and that would obviously be a lot slower. And so what we're doing here is
simply updating there to be a trigger. The report generation status
trigger and adding on a random element so that it's always gonna
change when we do this trigger. So this is very similar to what
we had when we were updating it through the bulk edit. And the next thing we need to do is come
down to there's a visibility element here, and we need to make sure that we
put a rule in here to say, show condition. On condition of this formula. And so we open up the formula bar here
and we're going to use a special condition here, which is basically saying that,
we only show this particular button, when the items selected is not empty. Because we want, we don't wanna show this
button when there are no items selected. So we'll save and publish
and wait for that. In our list of projects, I can just select
an account and I've got a subgrid here of all of the different projects that
are related to that particular account. And so in here you can see the project
generation status is, is empty. So let's just select these first four
in this state, in this this list. So what we've got is our generate
report power Fx button as you'd expect. And so we, if we run that, so now you
can see here the report generation status has got the trigger, which is great. And if we refresh this, you'll see
that eventually these will be complete. Let's refresh again. There we go. Completed. So we've got the ability now with our
power Fx button to run a flow on each of those items and notice if I don't have
any selected, that button is not visible. Well, what happens if we don't want
to have to keep on refreshing that that grid we want to run the flows and
have some feedback to the user so that they know that it is all completed? Well, currently, there's no way
of doing that inside power Fx. There's no way of displaying
a kind of a progress bar yet. And so if we wanna do that, we
are gonna have to use JavaScript. Or in this case I'm gonna use type script. So we've got the exactly
the same kind of scenario. We've got our model
driven out with our grid. We're gonna use a command bar using
modern command, we've, but rather than using power effects, we're
gonna actually run some JavaScript from a JavaScript web resource, and
that will do exactly the same thing. It will update the records. and that will trigger that flow. I have a free course that I'll
put link to below I on writing type script, web resources if
you wanna learn how to do that. In this case, I'm just gonna show
the code and show that hopefully that actually it's not too complicated. So here I have a type script project,
and the project has got a type script file called Project Ribbon, and we've got
a class called Project Ribbon in here. And I'm using a library called
dataverse-ify with dataverse-gen. And that's a library and open source
library that I've created that my free course shows you how to use. And it just simplifies
making calls to the web api. Making calls to update Dataverse
without having to, to construct http request or using a low level web API
call from using the XRM utilities. And so what we're doing here is that
we've got a top most trigger function, and this is the function that's gonna
be called from our command button. And it accepts a list of
entities in a, in an array. And I'll show you how
to do that in a minute. And what it does, it makes it
call to an internal function just using Promise.Resolve. And what that means is, is that it's
a fire-and-forget, we don't want to wait for this particular function
to run because otherwise the time there will be a timeout that the
JavaScript call will, will happen. So the model of an app will think that
the function is not actually done what it needs to do, but because we're doing that
fire-and-forget this function now runs. It does something very
similar to the power Fx. It sets this trigger to be, to
get, have a random element to it. And then what it's doing is it is
going and creating a set of updates. So what we've got here is we've got
a a set of update batches that it will pass in this particular shape
of object, which is saying that it's a logical name is project, and we're
giving the id of the project and we are setting the project generation
status to be trigger very much in the same way as we did with the Power Fx. So we've got, now we've got that set
of updates inside this batch an array. Now we can just simply make
this call to execute multiple. And so that will send a single batch
update with all those updates in it. And now what we can do is we can call
a FetchXML query to find out how many. Of the projects still have
their status set to that trigger that we just updated it. And that's, so that essentially doing
the same as when the user is clicking the refresh button, what we're doing
is we're counting how many are still in the trigger status and they haven't been
moved onto the the completion status. And so then what we do is we
then show the the progress. And so what we're using is we're using
this showProgressIndicator utility that comes as part of the XRM utility, and
it will show the number of projects that are currently have been completed versus
the number that we originally sent it on. And we're also gonna time out. We're only gonna do this
every two minutes now. All this code I'm gonna put
up available in a blog post. So you'll be able to
go and grab it as well. And so the, all that remains that
the end is just to close the progress indicator so that we know it's been done. So back over in the Subgrid editor
for projects, I've added in a new button here called Generate Reports,
but this is calling the JavaScript and it's basically the same as the
power Fx version, except I am making use of a JavaScript web resource. And what we're doing is we are,
now, we're going to call a function, which in this case is the create
report trigger function that we just looked at inside our type script. And we're passing in a parameter
called SelectedControlSelectedItemIds. And so that's that array of all the
IDs of the projects that we have selected in the sub grid so that we
can go and perform that batch update. So once we've saved and published that,
and we can go and play that and go over and we will get this little message
here to say a new version of the app is available, please refresh to update. So we'll refresh that and then
go over into the same place as we were before inside our accounts. And we'll open Contoso as we had
before, and if we look at the items down here, let's go into the second page. There we go. So let's just select some items here
and now go into our command bar. And you can see here we've
got generate reports (JS). So let's go and select that. And there we go. Generating reports. You can see here it's giving us the
number that have actually been completed. And you can see it's just incrementing. So the flows are running in the
background and it's running that FetchXML to determine how many
have actually been completed. So we didn't need to refresh this. Of course, if I refresh this now refresh
this grid, then we'll see that they all are marked as completed, obviously,
because our code was waiting for that. So up until this point, the flows
that we've been running have run for every single record that we selected. So if you select five records,
it will have five flow runs. Another option is to use a custom
page to run a single flow passing in a list of multiple records. And so we do this quite easily from a
grid using a little bit of JavaScript. So we would use a command button
as we did before, and we'd have a JavaScript function that would accept
as again, as we did before, a list or an array of all the selected items. And then this time, rather than actually
making the call inside JavaScript, we're gonna use the Navigate API to
show a custom page as a dialogue. Now I've got other videos of
showing you how to use custom pages. And in this case, we're going
to accept a parameter, which is Id passed from that JavaScript. And then we'll use Split to split it out
into individual GUIDs, unique identifiers of the various different projects. And then we'll pass that across to a
flow using and the power apps trigger. And so we can then split that up, and
and perform multiple actions in a loop inside our flow and then inside our custom
page, we can then do the same as we did in our JavaScript, we can kind of monitor
using a timer, monitor those records to check if they've been completed or not. So this time we are going to use our
main grid project main grid ribbon. And so I've got a button here
called generate reports similar to the JavaScript report generation
button that we had before. And the action in this circumstances
we're gonna run a different function in the same ways we did before passing
in SelectedControlSelectedItemIds. So an array of the the
IDs that are selected. And we have, again, the visibility
of this button is based on the selection in the grid. So if no items are selected,
it won't show the button. So if we go over into the JavaScript, this
is actually quite a simple JavaScript in that it has the same function parameter,
which is the entity IDs, the string array. But we are now just simply going to
pass in a set of parameters here which are the the page type is going to be
custom page and It's the name comes from the logical name of our custom
page in the solution, when we add a custom page, we can easily get that. And then what we're doing here
is we are simply joining all of the IDs together into a single
string using comma as a separator. And then the, the navigation options
Uh, we are, we've simply saying that it's gonna be a 2 means it's gonna
be a dialogue and position 2 means it's going to be a, a side panel and
we give it a little bit of width and we can give it the title as well. And then this last item here is simply
saying, Okay, we now gonna navigate to that custom page using those navigation
options that we've just defined above. So here I've got a custom page. We've got creator kit, details list and
just a button saying Create reports. And so this would be the custom page
that you would show in the sidebar. And so when we show the custom
page, it's gonna be become, it's gonna run this on visible event. So we're gonna put some code up here
to go and grab the various different parameters that we've passed into it. So we've got this record ID
parameter that got passed from our JavaScript, if you remember. So if you go into our JavaScript
you can see here that we are passing in the record ID parameter here. So we will split that eventually
based on the comma because obviously we passed it in with, with a, a
comma delimiter, and now we need to split it up into a set of records. And then what we're gonna do is
take that set of record IDs and go and grab individual project records
from the project data source. So I'm gonna go here and
add in a, the project table. So that will then resolve. And so we've now got a the
collection called colProjects. For each of the IDs that we had
passed in, we are going to get a project record in here that will have
the ID and the name and the status. So we can go and bind this
colProjects to our data grid here, and then we need to set the columns. I've got another video that
shows you how to do this. Set the columns to be a set
of simple definition of the status, and then the name. And, and so if we run this by
moving away and then coming back. We should now have a set of and
let's go and add in, make sure we've added in the fields, so
Id name and status, add that in. And there we go. We've got a name of the individual
project, and then we should also have a status column as well. Just take a look at that definition here. Okay. So it's because evidently I, cause I
took this from the completed app so it's actually trying to show it as an icon,
which obviously I haven't done yet. I'll show you how that works in a minute. But in the moment, I'm just
gonna display the status here. And let's just make the width of that. Yeah, that's fine. So now if we go back to that
here, the call name is Status Cell Type is not image. It's just gonna be a standard text. There we go. So we've now got it's showing
complete because that's what we had, we'd done these previously. The next thing we need to do is we
actually need to be able to run the flow on these items and then refresh
the display with the, the latest value. So we have to go and create that flow. And as I said before, we're not
going to pass in each individual. We're not gonna run the
flow multiple times. You're just gonna run the flow
passing in a, a collection. So if we go to on select here, and
we put this below code in here, what we're doing here is we're just
updating the status to be in progress. And then what we're gonna do is we
are going to, get a set of collections and convert it into a JSON string. And that's what we're going to
then pass into our our flow. And so let's take this varJSON and
just, just put it into a text box if we go down here so that we can go
and get the, see what it looks like. So I'm gonna put the value of this to be. varJSON obviously is empty at
the moment, but if I run create reports, you'll see now that it
has got a, a whole load of JSON. So if I extract that out and go
over to create another flow, So let's go back to our solution. And there's cloud flows
and I create a new one. And this time I'm gonna use an
instant flow because we're gonna trigger it from power apps. So there's, it's the power apps trigger
and we're gonna call it generate report 2 cause I've already got one. So power apps and then create. So we've got the power apps trigger,
and as I said before, we, we are going to, we're sending it a string
of Jason from our power apps. So we're gonna use the Parse JSON,
and we're going to ask in power apps. So we're gonna call this
the the selected record. So let's rename this selected records. So you can see here it's now
created selected records content. So that's now a parameter. To this flow and we can just paste
in, generate from sample, we can paste in that that JSON that we picked from
the the generated JSON in our app. So you can see there is now
created a nice schema for us. So now we have our parse JSON. Now we can go and do
another data operation. And we can map the the, json object
that has been passed into an array. So I'm going to select the
output of that that parsing. And I'm gonna go and grab for
each of those that just the id. I'm gonna call this
just the project array. Now we can just simply use this
so that, let's say we wanted to do in Microsoft Dataverse, we
wanted to go get some list rows. We could say, well, the project table,
and we could use a FetchXML query so we could pop some FetchXML in here. So this will get all of the projects
where the project ID is in, and there's a set of values here, and I'm gonna
put a dynamic expression in here, and we are going to put in a join. So the, this joins the outputs of
the selected record id, which is actually we need to make sure it's
called projects array like that. That's the output of that. And then we'll get the body of that
and we'll join it together using value. So what that'll end up with is
a list of values inside here. So once we've saved our flow and we
come over back to our custom page here, we can go and add a flow. And say, create project
reports and select that. And rather than inside create reports,
rather than just simply setting the variable there, what we can do is we can
say, create project report and we can then send that text over and so there
that will, that will trigger that flow, that will, the json will be passed split
into an array and we can perform various different things in a single flow. So we can actually do a loop over
that array and at the end of that, we will then update the trigger status
to say it's completed in much in the same way as we were doing before. So all that would remain is
in this app, is to actually go and refresh and monitor this. That does pose somewhat of a challenge
since there is a lot of caching that goes on inside canvas apps and so,
you know, for performance reasons. So if we want to refresh a grid,
we need to come up with some way of ensuring that we perform a query
that will always get the results rather than getting it from cache. So we flip over into what I prepared
earlier to see how I did that. So this is very similar
to what we just saw there. But if we go and if we look at the
grid, there's a subtle difference here in that rather than just simply
having a text version of the status, what we're doing here is we're adding
a couple of columns to actually convert that into an icon column with
an SVG to show like a spinning icon. And and the actual color of the
status, depending on the status that if it's completed or in progress. And then also on the create
reports on select here you'll see that it's very similar. But what we're gonna do is we are going
to set a context to say that this flow is running and that will then start a timer. And the timer will tick
away every two seconds. And on end of that
timer, the on timer end. If we look at the this is going
to run Select(btnRefreshFunction). So this is just simply an
easy way of encapsulating some common common functions that
you use over and over again. So I could call this from
multiple different places. And so what we're doing here is we
are creating a random filter seeds. So we're saying here that this is just a,
a simple random string, and we're using that random string inside our our filter. So each time we run this query, this
random element will be different. And so that forces the expression to
be reevaluated against the server. If this was always the same, then you
might get these results from a cache. And so every time we refresh, we're
gonna get a a new set of results. And so it's kind of one of those
workarounds, if you like, to caching. So let's take a look at that in action. I'm gonna run, generate reports here. And so you can see here it's
running that JavaScripts and showing the custom page with all of the
items that I've just selected. And I'll, I'll select, select,
create reports here, and it will then run that flow. And you can see here they're
all in the, in progress. And now that time has started ticking
away and the, the filter is going to run, and it's gonna gradually
see these results get completed. So there we have it and it's
all, it's all working and showing the the updated status. So that I think is five
ways of running a flow. So. If there is a different way that
you've used to run a flow you may have used Ribbon Workbench, the Smart
Buttons, web hook functionality. That may be a way you've used or maybe
you've used a different way in the past. Please let me know in the comments
and subscribe and like, and hopefully if you've liked what you see. I will see you next time. Have a great rest of your day. Cheers.