关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复229或者20161028可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me 。

要执行插件,需要对对记录做更改或者创建记录后触发事件才行,利用JavaScript不能直接调用插件,需要曲线救国,比如更改一个字段,然后保存记录触发插件。从Dynamics CRM 2016开始,JavaScript可以方便的调用操作了,这个应该是一个代替插件的一个方式。
我这里举出一个常用例子,命令栏的按钮,在记录保存后,用户对记录有修改权限,用户具有代理角色的时候按钮可见,叫提交,点击以后执行一些具有事务性的操作(多个步骤要么都成功,要么都失败,操作刚好也支持这个特性,如果用纯粹的JavaScript来做的话就不支持事务),然后当前页面提示操作成功2秒以后刷新页面,为啥要刷新页面?因为提交成功后有些字段只读了,你不刷新还是可以改写就会出问题。
操作的建立方法我就不说了,我建立了一个带字符串参数的操作如下,为什么要带一个参数呢?减少文件的数量,多个不同的操作的服务器端代码写在一块。
 
操作中调用了一个自定义工作流活动,代码如下:
  1. public sealed class TestOperations : CodeActivity
  2. {
  3. [Input("操作名称:提交/检测/维修/关闭")]
  4. [Default("提交")]
  5. public InArgument<string> OperationName { get; set; }
  6.  
  7. protected override void Execute(CodeActivityContext executionContext)
  8. {
  9. ITracingService tracingService = executionContext.GetExtension<ITracingService>();
  10.  
  11. //Create the context
  12. IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
  13. IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
  14. IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
  15. var userid = context.UserId;
  16. var initiatingUserId = context.InitiatingUserId;
  17. tracingService.Trace("userid=" + userid.ToString() + ";initiatingUserId=" + initiatingUserId);
  18. var operationName = executionContext.GetValue<string>(OperationName);
  19. tracingService.Trace("执行的操作是:" + operationName);
  20. if (operationName.Equals("提交"))
  21. {
  22. var testSubEntity = new Entity("ly_testsub");
  23. testSubEntity["ly_name"] = DateTime.Now.ToString();
  24. testSubEntity["ly_test"] = new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId);
  25. service.Create(testSubEntity);
  26. var noteEntity = new Entity("annotation");
  27. noteEntity["objectid"] = new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId);
  28. noteEntity["subject"] = DateTime.Now.ToString();
  29. service.Create(noteEntity);
  30. }
  31.  
  32. }
  33. }

然后我用来做按钮的RibbonDiff如下:

1. 统一使用EnableRule来设置可见性,因为要用到CustomRule,而DisplayRule不支持
这种调用JavaScript函数返回true/false的rule.
2.用户对当前记录有写权限请使用RecordPrivilegeRule,这个如果记录变成禁用了,
按钮也不会显示,或者是新建记录的时候也不会显示.
3.鼠标放到按钮上后显示的提示中详细提示是 ToolTipDescription ,简单提示是ToolTipTitle。
  1. <RibbonDiffXml>
  2. <CustomActions>
  3. <CustomAction Id="ly.ly_test.Submit.Button.CustomAction" Location="Mscrm.Form.ly_test.MainTab.Save.Controls._children" Sequence="75">
  4. <CommandUIDefinition>
  5. <Button Command="ly.ly_test.Submit.Command" Id="ly.ly_test.Submit.Button" Image32by32="/_imgs/ribbon/runreport32.png" Image16by16="/_imgs/ribbon/RunReport_16.png" LabelText="$LocLabels:ly.ly_test.Submit.Button.LabelText" Sequence="75" TemplateAlias="o2" ToolTipTitle="$LocLabels:ly.ly_test.Submit.Button.ToolTipTitle" ToolTipDescription="$LocLabels:ly.ly_test.Submit.Button.ToolTipDescription" />
  6. </CommandUIDefinition>
  7. </CustomAction>
  8. </CustomActions>
  9. <Templates>
  10. <RibbonTemplates Id="Mscrm.Templates" />
  11. </Templates>
  12. <CommandDefinitions>
  13. <CommandDefinition Id="ly.ly_test.Submit.Command">
  14. <EnableRules>
  15. <EnableRule Id="ly.ly_test.submitEnableRule.EnableRule" />
  16. </EnableRules>
  17. <DisplayRules />
  18. <Actions>
  19. <JavaScriptFunction FunctionName="submit" Library="$webresource:ly_/test/js/TestRibbon.js" />
  20. </Actions>
  21. </CommandDefinition>
  22. </CommandDefinitions>
  23. <RuleDefinitions>
  24. <TabDisplayRules />
  25. <DisplayRules>
  26. </DisplayRules>
  27. <EnableRules>
  28. <EnableRule Id="ly.ly_test.submitEnableRule.EnableRule">
  29. <RecordPrivilegeRule AppliesTo="PrimaryEntity" Default="false" InvertResult="false" PrivilegeType="Write" />
  30. <ValueRule Field="statuscode" Value="1" Default="false" InvertResult="false" />
  31. <CustomRule FunctionName="submitEnableRule" Library="$webresource:ly_/test/js/TestRibbon.js" Default="false" InvertResult="false" />
  32. </EnableRule>
  33. </EnableRules>
  34. </RuleDefinitions>
  35. <LocLabels>
  36. <LocLabel Id="ly.ly_test.Submit.Button.LabelText">
  37. <Titles>
  38. <Title description="提交" languagecode="0" />
  39. <Title description="提交" languagecode="2052" />
  40. </Titles>
  41. </LocLabel>
  42. <LocLabel Id="ly.ly_test.Submit.Button.ToolTipTitle">
  43. <Titles>
  44. <Title description="提交" languagecode="0" />
  45. <Title description="提交" languagecode="2052" />
  46. </Titles>
  47. </LocLabel>
  48. <LocLabel Id="ly.ly_test.Submit.Button.ToolTipDescription">
  49. <Titles>
  50. <Title description="提交看看" languagecode="0" />
  51. <Title description="提交看看" languagecode="2052" />
  52. </Titles>
  53. </LocLabel>
  54. </LocLabels>
  55. </RibbonDiffXml>
用到的按钮的JavaScript如下:
1. 使用了Xrm.Page.context.getUserRoles来传递用户拥有的角色ID,然后写了一个函数来判断
checkUserHasRoles用户是否拥有多个角色中的一个,一般允许系统管理员也进行操作。
2.JavaScript数组已经直接支持forEach,some等函数了,可以直接使用。
3.调用操作请注意使用了同步的请求来模拟插件。
4.刷新页面有点儿笨,当前页面提示成功等待两秒后刷新页面。
本来我想用别的办法,比如刷新后显示成功,可是不行,异步保存后提示也不好用。
  1. function submitEnableRule() {
  2. return checkUserHasRoles(Xrm.Page.context.getUserRoles(), ["系统管理员", "代理"]);
  3. }
  4. function submit() {
  5. var clientURL = Xrm.Page.context.getClientUrl();
  6. var recordId = Xrm.Page.data.entity.getId().replace(/^{/, "").replace(/}$/, "");
  7. var req = new XMLHttpRequest()
  8. req.open("POST", encodeURI(clientURL + "/api/data/v8.0/ly_tests(" + recordId + ")/Microsoft.Dynamics.CRM.ly_TestOperation"), false);//true是异步请求,false是同步请求
  9. req.setRequestHeader("Accept", "application/json");
  10. req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  11. req.setRequestHeader("OData-MaxVersion", "4.0");
  12. req.setRequestHeader("OData-Version", "4.0");
  13. req.onreadystatechange = function () {
  14. if (this.readyState == 4 /* complete */) {
  15. req.onreadystatechange = null;
  16. if (this.status == 204) {//204代表成功无返回值
  17. //刷新页面
  18. Xrm.Page.ui.setFormNotification("操作成功!", 'INFO', '00F041A1-2D30-4B30-9D12-63285716D8ED');
  19. setTimeout(function () {
  20. Xrm.Page.ui.clearFormNotification('00F041A1-2D30-4B30-9D12-63285716D8ED');
  21. Xrm.Utility.openEntityForm(Xrm.Page.data.entity.getEntityName(), Xrm.Page.data.entity.getId());
  22. }, 2000);
  23. }
  24. else {
  25. var error = JSON.parse(this.response).error;
  26. Xrm.Utility.alertDialog("错误:" + error.message);
  27. }
  28. }
  29. };
  30. var requestmsg = {};
  31. requestmsg.OperationName = "提交";
  32. req.send(JSON.stringify(requestmsg));
  33. }
  34. function checkUserHasRoles(roleIdArray, roleNames) {
  35. var roleIds = "", userRoles = [], ret = false;
  36. var clientURL = Xrm.Page.context.getClientUrl();
  37. roleIdArray.forEach(function (element) {
  38. roleIds += "roleid eq " + element + " or ";
  39. });
  40. roleIds = roleIds.replace(/\sor\s$/, '');
  41. var req = new XMLHttpRequest()
  42. req.open("GET", encodeURI(clientURL + "/api/data/v8.1/roles?$select=name&$filter=" + roleIds), false);//true是异步请求,false是同步请求
  43. req.setRequestHeader("Accept", "application/json");
  44. req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
  45. req.setRequestHeader("OData-MaxVersion", "4.0");
  46. req.setRequestHeader("OData-Version", "4.0");
  47. req.onreadystatechange = function () {
  48. if (this.readyState == 4) {
  49. req.onreadystatechange = null;
  50. if (this.status == 200) {
  51. var responseJSON = JSON.parse(this.responseText);
  52. if (responseJSON.value != null && responseJSON.value.length >= 1) {
  53. responseJSON.value.forEach(function (element) {
  54. if (roleNames.some(function (ele) { return ele == element.name })) {
  55. ret = true;
  56. }
  57. });
  58. }
  59. }
  60. }
  61. }
  62. req.send();
  63. return ret;
  64. }
  65. //# sourceURL=TestRibbon.js
提交按钮效果如下:
 

执行插件的替代方式:用JS调用操作的更多相关文章

  1. Js调用本地exe的方式

    1.     使用记事本(或其他文本编辑器)创建一个myprotocal.reg文件,并写入以下内容 Windows Registry Editor Version 5.00 [HKEY_CLASSE ...

  2. js调用后台方法(如果你能容忍执行的后台方法变成一个常量)

    最近一直在做一个电话拨号的系统,系统不大,但是做的时间有点长了.其中用到了一个技术:js调用后台方法.解决这个问题花了不少时间,现如今仍然还有些不明白的地方,今天跟大家分享一下.真正明白的同学欢迎指正 ...

  3. 浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序

    在Javascript定义一个函数一般有如下三种方式: 函数关键字(function)语句: function fnMethodName(x){alert(x);} 函数字面量(Function Li ...

  4. [iOS Hybrid实践:UIWebView中Html中用JS调用OC方法,OC执行JS代码]

    原理: 1.JS调用OC 每次webview执行跳转时都会被iOS给拦截,执行下面函数获得系统允许. 因此可以根据跳转信息转给系统,执行相应功能,比如打开相册等. // 网页中的每一个请求都会被触发 ...

  5. UIWebView中Html中用JS调用OC方法及OC执行JS代码

    HTML代码: <html> <head> <title>HTML中用JS调用OC方法</title> <meta http-equiv=&quo ...

  6. 意外作出了一个javascript的服务器,可以通过js调用并执行任何java(包括 所有java 内核基本库)及C#类库,并最终由 C# 执行你提交的javascript代码! 不敢藏私,特与大家分

    最近研发BDC 云开发部署平台的数据路由及服务管理器意外作出了一个javascript的服务器,可以通过js调用并执行任何java(包括 所有java 内核基本库)及C#类库,并最终由 C# 执行你提 ...

  7. vs2010开发activex(MFC)控件/ie插件(三),js调用ocx控件的接口函数

    原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/50802280   js调用ocx控件的接口函数,先看demo效果:      简单测试过程 ...

  8. ADO方式,VC调用Execute执行INSERT INTO插入变量SQL语句的写法

    ADO方式,VC调用Execute执行INSERT INTO插入变量SQL语句的写法 有些情况下,SQL SERVER 2008r2中需要保存float,int类型的数据,当C 中的变量为double ...

  9. JS调用函数的两种方式

    <script type="text/javascript"> window.onload = init; //onload 表示页面全部加载完毕后,再调用init() ...

随机推荐

  1. 微信小程序头像为什么是模糊的?小程序头像模糊怎么办?

    「柒留言」更新的换国旗头像小功能,获取头像显示模糊... 1.头像模糊 国庆之前,更新了「柒留言」小程序加国旗头像的小功能,但是头像模糊这个坑我在发布新版之前还没解决. 一直以为是代码出了问题,各种搜 ...

  2. 【转载】Android App应用启动分析与优化

    前言: 昨晚新版本终于发布了,但是还是记得有测试反馈app启动好长时间也没进入app主页,所以今天准备加个班总结一下App启动那些事! app的启动方式: 1.)冷启动  当启动应用时,后台没有该应用 ...

  3. ABP入门教程13 - 更新菜单

    点这里进入ABP入门教程目录 菜单更新 在展示层(即JD.CRS.Web.Mvc)的Startup下打开CRSNavigationProvider.cs //用以存放菜单相关信息 修改如下 using ...

  4. Fundebug网站升级HTTP/2,真的变快了!

    作为新一代的HTTP协议,HTTP/2可以提高网站性能,优化用户体验,Fundebug也是时候升级HTTP/2了,虽然已经有点晚了. 升级HTTP/2是一件很简单的事情,改1行Nginx配置就好了,但 ...

  5. 电池的QPNP模式

    名词解释: CV:Constant Voltage恒压 SMMB charger:Switch-ModeBattery Charger and Boost peripheral开关模式电池充电器和升压 ...

  6. Python-判断回文

    # 回文单词是从左到右和从右到左读相同的单词. # 例如:"detartrated"和"evitative"是回文 str_in = input('Input: ...

  7. Centos7配置桥接网络

  8. python配置yaml

    我们在做自动化的过程中无论是接口自动化还是UI自动化都会存在很多数据,我们对于自动化中如何存放这些数据也是很重要一点,如果写在代码里的话,每次更换数据就有点繁琐,我们可以通过一个文件存放这些数据,然后 ...

  9. 我的朋友&值得学习的大佬

    @media only screen and (max-width: 360px) { #friedsGroup { columns: 1 !important; } } #MySignature{ ...

  10. new和delete创建和释放动态数组

    1.动态创建和释放一维数组 #include<iostream> using namespace std; int main() { int n; cin>>n; //分配动态 ...