I am working with a Microsoft Powerapps application with .NET. I am using Web Templates to create custom pages in the app. I want to pass values between two templates. Any idea how can I do that? Currently, I am using the parameter approach using ajax calls like the below. But, I want to pass more than one value (ex: 50 values). How can I do that?
Template1:
Here I am making an ajax call to a service that is in another web template as follows:
var eid = eid;
$.ajax({
type: "GET",
url: "/getcodes/?eid="+eid,
data: "",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (res) {
var obj = res;
console.log(obj);
},
error: function (msg) {
//alert(msg);
}
});
Template2:
Here I am getting the parameter request and the value in the request and assigning it to a liquid variable. I am processing the variable received using the FETCHXML query and getting the data.
{%- assign eid = request.params['eid'] -%}
{% fetchxml contact %}
<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' no-lock='true'>
<entity name='entitlement' >
<attribute name='customerid' />
<attribute name='etid' />
<filter>
<condition attribute='etid' operator='eq' value='{{ eid }}' />
</filter>
</entity>
</fetch>
{% endfetchxml %}
So, My question here is: IS THERE ANY OTHER WAY TO PASS VALUES BETWEEN THE TEMPLATES OTHER THAN PARAMETERS?
Related
I'm trying to do a fetchXML query against my account list using the simple query provided here
Normally, I would expect this to respond with a json responses alongside the account I'm running a query for, but I'm instead getting this error message :
The request URI is not valid. Since the segment 'accounts' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource.
My actual URL request is :
https://<org>.crm.dynamics.com/api/data/v9.0/accounts(<actual_guid>)
Am I overlooking something? I originally had a more complex fetchXML request but made it as simple as I can think of to eliminate possible issue.
Thanks in advance for any help!
If you want to execute a FetchXML query against the Web API endpoint, the correct syntax is this one (jQuery example but you can see the endpoint url):
var originalFetchXML = '<fetch top="5" ><entity name="account" ><attribute name="accountid" /><attribute name="name" /></entity></fetch>';
var escapedFetchXML = encodeURIComponent(originalFetchXML);
$.ajax({
type: "GET",
url: Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.1/accounts?fetchXml=" + escapedFetchXML,
async: true,
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json",
"Prefer": "odata.include-annotations=*"
},
success: function (data, textStatus, xhr) {
var results = data;
console.log(results);
},
error: function (xhr, textStatus, errorThrown) {
console.log(xhr);
}
});
you didn't write which exact language you are using to execute the query, but if is JavaScript (Xrm.WebApi, Fetch API, jQuery or XHR) you can use Dataverse REST Builder to generate it, executing Fetch XML is under the Predefined Query request type and Query Type as FetchXML
I am using the hosted version of Locomotive CMS.
Locomotive CMS provides a means by which to collect form submissions and a means by which to send an email using the Actions API.
I want to collect form submissions and then send an email to the person who submitted the form.
I have 3 caveats:
I wish to collect the form data in a content type (public submissions enabled)
I wish to use Google reCAPTCHA v3
I wish to submit the form using AJAX
All of the aforementioned items are available out of the box in the hosted version of Locomotive CMS. However, I can't figure out how to submit a content type form with Google reCAPTCHA via AJAX and send an email at the same time. The Send Email functionality requires an action on a dedicated page which I believe needs to be loaded in order for the action to run. Additionally I don't know how to get the data from the form submission to the page on which the Send Email action runs.
How can I submit a Locomotive CMS content type form via AJAX with Google reCAPTCHA enabled and send an email containing the form submission data to the person who submitted in the form?
A couple of prerequisites:
Set up metafields_schema.yml to include the necessary information for sending emails:
smtp_settings:
label: Outgoing Email
fields:
server:
label: SMTP Server
type: string
localized: false
username:
label: Username
type: string
localized: false
password:
label: Password
type: string
localized: false
port:
label: Port
type: string
hint: TLS
localized: false
Set up an email template:
email-template.liquid:
<p>Dear {{ entryData.first_name }},</p>
<!-- include form submission data via entryData.form_field_name -->
If the condition of using Google reCAPTCHA is removed, the task is relatively straight-forward.
We "simply" pass the form data to a custom page where we send an email and create a content entry using the Actions API.
Setup as follows:
Manually create a form to collect the content type data. Note the form action points to a custom page:
<form method="POST" enctype="multipart/form-data" class="form" action="{% path_to 'page-with-send-email-and-create-content-entry-action' %}">
<!-- form fields here -->
</form>
<script defer src="{{ 'form-submit.js' | javascript_url }}"></script>
Submit the form with AJAX:
form-submit.js:
$('.form').on('submit', function(e) {
e.preventDefault();
var form = $(this);
// error handling functions removed for brevity
$.ajax({
type: 'POST',
url: form.attr('action'),
data: form.serialize(),
dataType: 'json',
success: function(data) {
console.log('Success:', data);
},
error: function(xhr, status, error) {
console.log('Status:', status);
console.log('Error:', error);
var errors = jQuery.parseJSON(xhr.responseText).errors;
console.log(errors);
for (error in errors) {
myError = error;
console.log(myError);
}
}
});
});
Send an email and create a content type entry using the Actions API:
page-with-send-email-and-create-content-entry-action.liquid:
{% action "send email and create content type entry" %}
var SMTPsettings = getProp('site').metafields.smtp_settings;
var entryData = getProp('params'); // params holds the data passed to the page via AJAX
// save entryData into a Liquid variable to be called in the Email Template
setProp('entryData',entryData);
sendEmail({
to: formData.email_address, // must match the name attribute of the field used to collect the email address
from: SMTPsettings.username,
subject: '[Email Subject]',
page_handle: 'email-template', // template page for email
smtp: {
address: SMTPsettings.server,
port: SMTPsettings.port,
user_name: SMTPsettings.username,
password: SMTPsettings.password,
authentication: 'plain',
enable_starttls_auto: true
}
});
createEntry('content_entry_name', {
content_type_field_name: formData.form_field_name,
// comma-separated list - last item has no comma
});
{% endaction %}
{"success":true}
If Google reCAPTCHA is required, the task is more complex.
I don't believe there is a way to manually create a form in Locomotive CMS with Google reCAPTCHA enabled, which means the above method won't work.
Google reCAPTCHA is available in Locomotive CMS via the default content type form setup:
{% model_form 'content_type_slug', class: 'form', json: true, recaptcha: true %}
// form fields here
{% endmodel_form %}
<script src="https://www.google.com/recaptcha/api.js?render={{ site.metafields.google.recaptcha_site_key }}"></script>
<script>
grecaptcha.ready(function() {
grecaptcha.execute('{{ site.metafields.google.recaptcha_site_key }}', {
action: 'enquiry'
})
.then(function(token) {
document.getElementById('g-recaptcha-response').value = token;
});
});
</script>
<script defer src="{{ 'form-submit.js' | javascript_url }}"></script>
Note: The property recaptcha_required needs to be set to true in the content_type yml file.
In this case we cannot set a custom url for the form action. Additionally the reCAPTCHA verification means we need to let the form submit and create the content entry via the usual process and send the email separately.
To do this we will need to get the ID of the content entry created upon form submission. We can then run an additional AJAX request and pass the ID to a custom page containing a send email action. On the custom page we will use the ID to reference the content entry and get the data to populate the email.
Setup as follows:
Create form via default method above.
Submit the form with AJAX. Upon successful submission, get the content entry ID and pass it to a secondary AJAX request:
form-submit.js:
$('.form').on('submit', function(e) {
e.preventDefault();
var form = $(this);
// error handling functions removed for brevity
$.ajax({
type: 'POST',
url: form.attr('action'),
data: form.serialize(),
dataType: 'json',
success: function(data) {
console.log('Success:', data);
// get the content entry ID
var entryID = data._id;
// set up the data to be sent in the correct format
var newData = 'id=' + entryID;
// set up our secondary AJAX request
function sendEmail() {
$.ajax({
type: 'POST',
url: 'page-with-send-email-action',
data: newData,
dataType: 'json',
success: function(data) {
console.log('Success:', data);
},
error: function(xhr, status, error) {
console.log('Status:', status);
console.log('Error:', error);
var errors = jQuery.parseJSON(xhr.responseText).errors;
console.log(errors);
for (error in errors) {
myError = error;
console.log(myError);
}
}
});
}
sendEmail();
showSuccess();
},
error: function(xhr, status, error) {
console.log('Status:', status);
console.log('Error:', error);
var errors = jQuery.parseJSON(xhr.responseText).errors;
console.log(errors);
for (error in errors) {
myError = error;
console.log(myError);
showError();
}
}
});
});
Find the submitted content entry and send an email using the Actions API:
page-with-send-email-action.liquid:
{% action "send email" %}
var SMTPsettings = getProp('site').metafields.smtp_settings;
var entryID = getProp('params').id;
var entryData = findEntry('content_type_slug', entryID);
// save entryData into a Liquid variable to be called in the Email Template
setProp('entryData',entryData);
sendEmail({
to: entryData.email_address,
from: SMTPsettings.username,
subject: '[Email Subject]',
page_handle: 'email-template',
smtp: {
address: SMTPsettings.server,
port: SMTPsettings.port,
user_name: SMTPsettings.username,
password: SMTPsettings.password,
authentication: 'plain',
enable_starttls_auto: true
}
});
{% endaction %}
{"success":true}
I have several views where I'm passing values to an external web service via an ajax post when the user clicks on submit or other action. For the url section of the ajax call I'm trying to pass a key from API.config, located in the Solution Items folder, where the value is different in each build/environment -
Solution Items folder layout
Key I'd like to pass to the ajax url: (API.config)
<appSettings>
<add key="RestApiEndpointBaseUrl" value="http://devserver/api/" xdt:Locator="Match(key)" xdt:Transform="SetAttributes"/>
Script within the view: (index.cshtml)
<script type="text/javascript">
var BaseUrl = '#System.Configuration.ConfigurationManager.AppSettings["RestApiEndpointBaseUrl"]';
$('#login').click(function () {
var note = {"Account":"#Model.AccountNumber","Text":"Log In","ActionCode":"CW","ResultCode":"LI","SequenceNumber":1,"UserId":"WEB"};
$.ajax({
type: "POST",
data: JSON.stringify(note),
url: BaseUrl + "Note",
contentType: "application/json"
});
});
</script>
Also, if I add "ToString()" to the end of the variable declaration like this -
var BaseUrl = '#System.Configuration.ConfigurationManager.AppSettings["RestApiEndpointBaseUrl"].ToString()';
I get a NullReferenceException error.
Otherwise, I get an empty string for the url. I'm not sure what I'm missing or doing wrong.
How, or Can I properly pass this as the url of the ajax call?
I want to pass html content for example the body content to a wcf service through ajax call, its saying URL is too long. Can this be solved
Assign html content in javascript variable and use below code.
var html_content= "<html...content>";
$.ajax({
url: "ajax.php",//file_name
type: "POST",
data: {
content: html_content
},
});
I have two apps. The first is WCF Service, the second is asp.net MVC 3 app.
In the WCF app I have a interface:
[ServiceContract]
public interface IService1
{
[OperationContract]
string HelloWorld(string personName);
}
And a class:
public class Service1 : IService1
{
public string HelloWorld(string personName)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize("Hello " + personName);
}
}
Now, in the asp.net mvc app I want call this method via Ajax:
<script type="text/javascript">
var personName = "John";
var dataIn = '{' + '"input":"' + personName + '"}';
$.ajax({
url: "http://localhost:7215/Service1.svc/HelloWorld",
type: "POST",
contentType: "application/json; charset=utf-8",
data: dataIn,
dataType: "json",
success: function (data) {
var object = JSON.parse(data.d);
if (object.Error == '') {
$("#response").html(object);
}
},
error: function (error) {
alert("Error: " + error);
}
});
</script>
But in the Firebug I get error: 400 Bad Request.
How to call HelloWorld method properly?
Thanks.
So you are trying to consume a WCF service from JavaScript?
The first problem I see is, your service is not yet ready to be consumed from JavaScript :(. You have to make the following changes..
Configure the Service1 class with the AspNetCompatibilityRequirements behavior.
Mark the service method HelloWorld in interface with WebGet attribute.
[You need reference to System.SericeModel.Web assembly]
After making the two changes..
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
string HelloWorld(string personName);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public string HelloWorld(string personName)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
// you are not returning data in proper JSON format, wrap the text in
// an anonymous object before serializing.
return serializer.Serialize(new { text = "Hello " + personName });
}
}
Next..
Configure webHttpBinding for the service (Make sure you change the service and contract names!).
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJsonP" />
</webHttpBinding>
</bindings>
<services>
<service name="MvcApplication3.Service1">
<endpoint address="" binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJsonP"
contract="MvcApplication3.IService1"
behaviorConfiguration="webHttpBehavior"/>
</service>
</services>
</system.serviceModel>
So now the service is ready!
Lets do the changes in the client-side (You are getting some data from the service so why POST?)
<script type="text/javascript">
var personName = "John";
var dataIn = '{' + '"input":"' + personName + '"}';
$.ajax({
url: "http://localhost:50623/Service1.svc/HelloWorld",
type: "GET",
contentType: "application/json; charset=utf-8",
data: dataIn,
dataType: "json",
success: function (data) {
var jsonData = JSON.parse(data);
$("#response").html(jsonData.text);
},
error: function (error) {
alert("Error: " + error);
}
});
</script>
Till now I've assumed that both the WCF service and the MVC app are running in the same domain.
But if that's not the case then you will gete a 405(Method Not Allowed) error due to CROSS-DOMAIN BARRIER.
There are different ways to overcome this problem!
1. Use JSONP
In this case you have to set the crossDomainScriptAccessEnabled property to true in the binding and you have to make JSONP calls from jQuery.
<binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" />
Then change the dataType from "json" to "jsonp" in the $.ajax method.
<script type="text/javascript">
var personName = "John";
var dataIn = '{' + '"input":"' + personName + '"}';
$.ajax({
...
dataType: "jsonp",
...
});
</script>
2. Using CORS
Refer this..
http://www.w3.org/TR/cors/
https://developer.mozilla.org/en/http_access_control
The first thing that you need to ensure is that you are not violating the same origin policy that's built in browsers. This policy prevents you from sending cross domain AJAX request. Since you mentioned that you have 2 applications I suspect that you are hitting this limitation because you have for example the first application hosted on http://localhost:1234/ (the one that contains the javascript file) and you are attempting to send an AJAX request to http://localhost:7215/ (same domain, different port => same origin policy is violated).
There are several workarounds. One of them consists into configuring the service to send a JSONP response instead of JSON. Here's a sample WCF service application on MSDN which illustrates how you could configure it. Basically you need to enable the crossDomainScriptAccessEnabled switch as shown in this blog post.