I'm trying to implement Klarna checkout to accept payments.
When creating an order (first step of the checkout) you receive a "html_snippet" as response from Klarnas API (in my case to express backend). It requires that this snippet is shown in the front end (in my case react).
Having read Klarnas documentation, I still cant figure out how to show this html snippet in react. Even copy pasting the exact snippet gives me 41 error warnings.
The snippet looks like this:
html_snippet: '<div id="klarna-checkout-container" style="overflow: hidden;">\n' +
' <div id="klarna-unsupported-page">\n' +
' <style type="text/css">\n' +
' #-webkit-keyframes klarnaFadeIn{from{opacity:0}to{opacity:1}}#-moz-keyframes klarnaFadeIn{from{opacity:0}to{opacity:1}}#keyframes klarnaFadeIn{from{opacity:0}to{opacity:1}}#klarna-unsupported-page{opacity:0;opacity:1\\9;-webkit-animation:klarnaFadeIn ease-in 1;-moz-animation:klarnaFadeIn ease-in 1;animation:klarnaFadeIn ease-in 1;-webkit-animation-fill-mode:forwards;-moz-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-duration:.1s;-moz-animation-duration:.1s;animation-duration:.1s;-webkit-animation-delay:5s;-moz-animation-delay:5s;animation-delay:5s;text-align:center;padding-top:64px}#klarna-unsupported-page .heading{font-family: "Klarna Headline", Helvetica, Arial, sans-serif;color: rgb(23, 23, 23);font-size: 36px;letter-spacing: -0.2px;-webkit-font-smoothing: antialiased;}#klarna-unsupported-page .subheading{font-family: "Klarna Text", "Klarna Sans", Helvetica, Arial, sans-serif;color: rgb(23, 23, 23);-webkit-font-smoothing: antialiased;line-height: 28px;font-weight: 400;font-size: 19px;max-width: 640px;margin: 20px auto;}#klarna-unsupported-page .reload {cursor: pointer;outline: none;-webkit-tap-highlight-color: rgba(255, 255, 255, 0);border-width: 1px;background-color: rgb(38, 37, 37);border-color: rgb(38, 37, 37);padding: 15px 24px;margin-top: 15px;color: rgb(255, 255, 255);font-family: "Klarna Text", "Klarna Sans", Helvetica, Arial, sans-serif;font-weight: 500;text-rendering: geometricprecision;font-size: 100%;}\n' +
' </style>\n' +
' <h1 class="heading">Something went wrong</h1>\n' +
' <p class="subheading">Sorry for any inconvenience, please try reloading the checkout page or try again later.</p>\n' +
' <p class="subheading">If the problem persists it maybe be because you are using an old version of the web browser which is not safe nor compatible with modern web sites. For a smoother checkout experience, please install a newer browser.</p>\n' +
' <button class="reload" onclick="reloadCheckoutHandler && reloadCheckoutHandler()">Reload checkout</button>\n' +
' </div>\n' +
' <script id="klarna-checkout-context" type="text/javascript">\n' +
' /* <![CDATA[ */\n' +
' var reloadCheckoutHandler;\n' +
' (function(w,k,i,d,n,c,l){\n' +
' w[k]=w[k]||function(){(w[k].q=w[k].q||[]).push(arguments)};\n' +
' l=w[k].config={\n' +
' container:w.document.getElementById(i),\n' +
" ORDER_URL:'https://js.playground.klarna.com/eu/kco/checkout/orders/dae844ba-c44a-6e55-b5ad-9afe9055e1f4',\n" +
" AUTH_HEADER:'KlarnaCheckout 4mpla37op0i19pv6g054',\n" +
" LOCALE:'en-GB',\n" +
" ORDER_STATUS:'checkout_incomplete',\n" +
" MERCHANT_NAME:'Your business name',\n" +
' GUI_OPTIONS:[],\n' +
' ALLOW_SEPARATE_SHIPPING_ADDRESS:false,\n' +
" PURCHASE_COUNTRY:'gbr',\n" +
" PURCHASE_CURRENCY:'GBP',\n" +
' TESTDRIVE:true,\n' +
" BOOTSTRAP_SRC:'https://js.playground.klarna.com/kcoc/220119-c2c224d/checkout.bootstrap.js',\n" +
" FE_EVENTS_DISABLED:'false',\n" +
" DEVICE_RECOGNITION_URL:'https://js.playground.klarna.com/eu/kco/checkout/orders/dae844ba-c44a-6e55-b5ad-9afe9055e1f4/device_recognition',\n" +
' DEVICE_RECOGNITION_TYPE1:true,\n' +
" DEVICE_RECOGNITION_TYPE3_ORG_ID:'87rxrdob',\n" +
" DEVICE_RECOGNITION_TYPE3_REF:'KLRNA_87rxrdob_dae844ba-c44a-6e55-b5ad-9afe9055e1f4',\n" +
" CLIENT_EVENT_HOST:'https://eu.playground.klarnaevt.com'\n" +
' };\n' +
" n=d.createElement('script');\n" +
' c=d.getElementById(i);\n' +
' n.async=!0;\n' +
' n.src=l.BOOTSTRAP_SRC;\n' +
' c.appendChild(n);\n' +
' try{\n' +
" ((w.Image && (new w.Image))||(d.createElement && d.createElement('img'))||{}).src =\n" +
" l.CLIENT_EVENT_HOST + '/v1/checkout/snippet/load' +\n" +
" '?sid=' + l.ORDER_URL.split('/').slice(-1) +\n" +
" '&order_status=' + w.encodeURIComponent(l.ORDER_STATUS) +\n" +
" '×tamp=' + (new Date).getTime();\n" +
' }catch(e){}\n' +
' reloadCheckoutHandler = function () {\n' +
' try{\n' +
" ((w.Image && (new w.Image))||(d.createElement && d.createElement('img'))||{}).src =\n" +
" l.CLIENT_EVENT_HOST+'/v1/checkout/snippet/reload?sid='+l.ORDER_URL.split('/').slice(-1)+\n" +
" '&order_status='+w.encodeURIComponent(l.ORDER_STATUS)+'×tamp='+(new Date()).getTime();\n" +
' window.location.reload();\n' +
' }catch(e){}\n' +
' }\n' +
" })(this,'_klarnaCheckout','klarna-checkout-container',document);\n" +
' /* ]]> */\n' +
' </script>\n' +
' <noscript>\n' +
'Please enable JavaScript.\n' +
' </noscript>\n' +
'</div>'
Anyone been through this journey?
You may have already solved this, but I used Iframe to render the snippet. Make an HTML page with the received snippet inside and use that as the source for your Iframe.
<iframe
title='klarnaCheckout'
className='iframe'
srcDoc={klarnaHtml(klarna.html_snippet)}
frameBorder='0'
></iframe>
export const klarnaHtml = (snippet) => {
return `
<html>
<head> </head>
<body>
<textarea style="display: none" id="KCO">
${snippet}
</textarea
>
<div id="my-checkout-container"></div>
<!-- START - Dont edit -->
<script type="text/javascript">
var checkoutContainer = document.getElementById(
"my-checkout-container"
);
checkoutContainer.innerHTML = document
.getElementById("KCO")
.value.replace(/\\"/g, '"')
.replace(/\\n/g, "");
var scriptsTags = checkoutContainer.getElementsByTagName("script");
for (var i = 0; i < scriptsTags.length; i++) {
var parentNode = scriptsTags[i].parentNode;
var newScriptTag = document.createElement("script");
newScriptTag.type = "text/javascript";
newScriptTag.text = scriptsTags[i].text;
parentNode.removeChild(scriptsTags[i]);
parentNode.appendChild(newScriptTag);
}
</script>
<!-- END -->
</body>
</html>
`;
};
Related
How do i loop through the enitre datset within the in datatables method?
"fnFooterCallback": function (nFoot, aData, iStart, iEnd, aiDisplay) {
$(aData).each(function (index) {
$(".it").append("<div class='mapdata' id='" + nFoot + "B' title='" + aData[index][14] + "|" + aData[index][15] + "' >");
});
},
The above works if the pagination is removed. But if iDisplayLength is set to 25 for example then it only goes through 25 records, not all 100 etc.
"fnFooterCallback": function (nFoot, aData, iStart, iEnd, aiDisplay) {
$(aData).each(function (index) {
$(".it").append("<div class='mapdata' id='" + nFoot + "B' title='" + aData[index][14] + "|" + aData[index][15] + "' data-id='true' data-id2='" + aData[index][1] + "' data-isapprove='" + aData[index][12] + "' ><div class='gTab1'><div class='info'><div class='maptitle'>" + aData[index][1] + "</div><div class='location'></div></div></div ></div >");
});
},
The above did it
I want to use a custom label inside a list that I then bind to a multi picklist.
<aura:attribute name="genderOptions" type="List"
default="[
{'label': {!$Label.c.DM_Gender_Male},'Value':
'Male'},
{'label': {!$Label.c.DM_Gender_Female}, 'value':
'Female'}
]"
/>
When I try to save the component, then I get the following exception (FIELD INTEGRITY EXCEPTION)
Failed to save DMSegmentation.cmp: Cannot mix expression and literal string in attribute value, try rewriting like {!'foo' + v.bar}: Source
Can someone help me to resolve this ?
Actually it is possible to create this inside the component. The two things you were missing are:
Quotes " need to be represented as XML escape entities.
Open and closing braces { } need to be represented as custom labels.
The component:
<aura:component >
<aura:attribute
name="genderOptions"
type="List"
default="{! ' [ '
+ $Label.c.LEFT_CURLY_BRACKET
+ '"' + 'label' + '"'
+ ' : ' + '"' + $Label.c.DM_Gender_Male + '"'
+ ' , ' + '"' + 'value' + '"'
+ ' : ' + '"' + 'Male' + '"'
+ $Label.c.RIGHT_CURLY_BRACKET
+ ' , '
+ $Label.c.LEFT_CURLY_BRACKET
+ '"' + 'label' + '"'
+ ' : ' + '"' + $Label.c.DM_Gender_Female + '"'
+ ' , ' + '"' + 'value' + '"'
+ ' : ' + '"' + 'Female' + '"'
+ $Label.c.RIGHT_CURLY_BRACKET
+ ' ] '
}"
/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
</aura:component>
The custom labels:
<?xml version="1.0" encoding="UTF-8"?>
<CustomLabels xmlns="http://soap.sforce.com/2006/04/metadata">
<labels>
<fullName>LEFT_CURLY_BRACKET</fullName>
<language>en_US</language>
<protected>false</protected>
<shortDescription>LEFT CURLY BRACKET</shortDescription>
<value>{</value>
</labels>
<labels>
<fullName>RIGHT_CURLY_BRACKET</fullName>
<language>en_US</language>
<protected>false</protected>
<shortDescription>RIGHT CURLY BRACKET</shortDescription>
<value>}</value>
</labels>
<labels>
<fullName>DM_Gender_Male</fullName>
<language>en_US</language>
<protected>false</protected>
<shortDescription>DM_Gender_Male</shortDescription>
<value>♂</value>
</labels>
<labels>
<fullName>DM_Gender_Female</fullName>
<language>zh_CN</language>
<protected>false</protected>
<shortDescription>DM_Gender_Female</shortDescription>
<value>♀</value>
</labels>
</CustomLabels>
A client-side controller to get the value of the attribute and log it in the console:
({
doInit :
function( component , event , helper ){
var list = component.get("v.genderOptions")
console.log( list )
console.log( JSON.parse( list ) )
}
, f :
function(){
}
})
The logged result:
I found the solution. The only solution is to access these list through the client side controller available in the bundle and then populate it with the custom labels. Otherwise, lightning does not allow you to use custom labels inside lists created in the component. Have to use the doInit method for this
({
doInit: function(component, event, helper) {
var values = [
$A.get("$Label.c.DM_Gender_Male"),
$A.get("$Label.c.DM_Gender_Female")
];
component.set('v.genderOptions', values);
}
})
is it possible to use the angular-translate (pascaltrend) plugin within an ng-style in AngularJS:
I have:
<div class="inspiration-wrapper" ng-style="{'background-image': 'url(//' + S3_BUCKET + '.' + PHOTO_SERVER_URL + '/img/departures/' + departurePhoto + ')'}">
and I need something like:
<div class="inspiration-wrapper" ng-style="{'background-image': 'url(//' + S3_BUCKET + '.' + PHOTO_SERVER_URL + '/img/departures/' + departurePhoto | translate + ')'}">
this should work
<div class="inspiration-wrapper" ng-style="{'background-image': 'url({{'/' + S3_BUCKET + '.' + PHOTO_SERVER_URL + '/img/departures/'}}{{'departurePhoto' | translate }})'}"></div>
I'm asuming you have this as variable in scope
S3_BUCKET and PHOTO_SERVER_URL
I need get the initial value of a comboBox to charge a tooltip on my application, i got this method but this not charge nothing
var raw = ComboRegisted.combo.getRawValue();
Ext.QuickTips.register({ target: ComboRegisted.combo.getEl(), text: COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaFechaAprobacion") + raw.fechaAprobacion +
"<br/>" + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaCO") + raw.normaCO + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaUnidad1") +
"<br/>" + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaHC") + raw.normaHC + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaUnidad1") +
"<br/>" + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaNox") + raw.normaNox + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaUnidad1") +
"<br/>" + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaPM") + raw.normaPM + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaUnidad1") +
"<br/>" + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaHumo") + raw.normaHumo + COREProxy.languageMng.getText(oThis.CLASS_NAME, "tooltipNormativaUnidad2" )});
this.comboMap.register(ComboRegisted.ID, ComboRegisted.meta, ComboRegisted.combo);
No problem i get the answer now.
I do this:
var recordSelected = ComboRegisted.combo.store.getAt(ComboRegisted.combo.getValue());
var raw = recordSelected.raw;
and this go good.
My JavaScript spits out dynamic HTML with one of the fields as checkbox based on a boolean as follows:
<input type="checkbox" disabled='true' (bool == true ? "Checked":"undefined") />
My checkbox always returns checked even if the Boolean is false .
Any suggestions to doing that by ternary operation?
Also i just realized that it would be hard to have id's for each row of checkboxes. Here is how my function currently looks like:
function fnBuildWebSiteClipHtml(name, url, id, allow_removal, use_full_screen) {
var html = "<tr id='wc_" + id + "'>" +
tdstart + "<div style='float: left; width: 20px'><img src='/emm/websiteIcon.do?id="+id+"' height='16px' width='16px'/></div><div style='float: left; vertical-align: middle;'>" + OrionCore.escapeHtml(name) + "</div></td>" +
tdstart + OrionCore.escapeHtml(url) + "</td>" +
tdstart + "<input type='checkbox' disabled='true' " + (allow_removal ? "checked='true'" : "") + "/>" + "</td>" +
tdstart + "<input type='checkbox' disabled='true' " + (use_full_screen ? "checked='true'" : "") + "/>" + "</td>" +
tdstart +
"<table>" +
"<tr>" +
"<td><a href='javascript:fnShowWebsiteclip(" + id + ")'>"+MESSAGES.edit+"</a> | </td>" +
"<td><a href='javascript:fnDeleteWebsiteclip(" + id + ")'>"+MESSAGES.del +"</a></td>" +
"</tr>" +
"</table>" +
"</td>" +
"</tr>";
return html;
}
Line 8 where i check the allow_removal and then following line with check for use_full_screen is what i am trying to have my checkboxes follow. Any suggestions towards that are much appreciated.
Thanks for an already posted response but i am not sure how to fit that here in this situation.
May be you need it?
<body onload="(bool ==true) ? document.getElementById('myTernaryCheckBox').setAttribute('checked', 'checked') : false">
<input type="checkbox" disabled id="myTernaryCheckBox"/>
</body>