Sap Analytics Cloud (Application/Script) search datasource field for specific character - javascript

I am building a SAC analytic application and have never used javascript before. I have created a variable called Var_NextEvent. My datasource has a field that will contain A if the event is active. It may or may not have an active event but will never have more than one.
I want to search the field for "A" and if it finds it return the event name and store in variable for me to use in dynamic text box.
In the below example I would be storing 'Test2' in my variable.
Test Data
This almost does what I need but instead of assigning "Active Event Identified" to the script variable when A is found I want to assign the value from the event name column.
var members = tbl_Mega.getDataSource().getMembers("4PRT001-EVENTSTATUS");
for (var i = 0;i <= members.length; i++) {
if (members[i].description.includes("A")) {
Var_ActiveEvent = true;
Var_NextEvent = "Active Event Identified";
break;
}
Var_ActiveEvent = false;
Var_NextEvent = "No Active Events";
break;
}
So to clarify if Event Status = A then look at the Event name and store in my variable. I hope this make sense.
Any help appreciated thank you.

Related

Google Scripts - keep track of element [duplicate]

Update: This is a better way of asking the following question.
Is there an Id like attribute for an Element in a Document which I can use to reach that element at a later time. Let's say I inserted a paragraph to a document as follows:
var myParagraph = 'This should be highlighted when user clicks a button';
body.insertParagraph(0, myParagraph);
Then the user inserts another one at the beginning manually (i.e. by typing or pasting). Now the childIndex of my paragraph changes to 1 from 0. I want to reach that paragraph at a later time and highlight it. But because of the insertion, the childIndex is not valid anymore. There is no Id like attribute for Element interface or any type implementing that. CahceService and PropertiesService only accepts String data, so I can't store myParagraphas an Object.
Do you guys have any idea to achieve what I want?
Thanks,
Old version of the same question (Optional Read):
Imagine that user selects a word and presses the highlight button of my add-on. Then she does the same thing for several more words. Then she edits the document in a way that the start end end indexes of those highlighted words change.
At this point she presses the remove highlighting button. My add-on should disable highlighting on all previously selected words. The problem is that I don't want to scan the entire document and find any highlighted text. I just want direct access to those that previously selected.
Is there a way to do that? I tried caching selected elements. But when I get them back from the cache, I get TypeError: Cannot find function insertText in object Text. error. It seems like the type of the object or something changes in between cache.put() and cache.get().
var elements = selection.getSelectedElements();
for (var i = 0; i < elements.length; ++i) {
if (elements[i].isPartial()) {
Logger.log('partial');
var element = elements[i].getElement().asText();
var cache = CacheService.getDocumentCache();
cache.put('element', element);
var startIndex = elements[i].getStartOffset();
var endIndex = elements[i].getEndOffsetInclusive();
}
// ...
}
When I get back the element I get TypeError: Cannot find function insertText in object Text. error.
var cache = CacheService.getDocumentCache();
cache.get('text').insertText(0, ':)');
I hope I can clearly explained what I want to achieve.
One direct way is to add a bookmark, which is not dependent on subsequent document changes. It has a disadvantage: a bookmark is visible for everyone...
More interesting way is to add a named range with a unique name. Sample code is below:
function setNamedParagraph() {
var doc = DocumentApp.getActiveDocument();
// Suppose you want to remember namely the third paragraph (currently)
var par = doc.getBody().getParagraphs()[2];
Logger.log(par.getText());
var rng = doc.newRange().addElement(par);
doc.addNamedRange("My Unique Paragraph", rng);
}
function getParagraphByName() {
var doc = DocumentApp.getActiveDocument();
var rng = doc.getNamedRanges("My Unique Paragraph")[0];
if (rng) {
var par = rng.getRange().getRangeElements()[0].getElement().asParagraph();
Logger.log(par.getText());
} else {
Logger.log("Deleted!");
}
}
The first function "marks" the third paragraph as named range. The second one takes this paragraph by the range name despite subsequent document changes. Really here we need to consider the exception, when our "unique paragraph" was deleted.
Not sure if cache is the best approach. Cache is volatile, so it might happen that the cached value doesn't exist anymore. Probably PropertiesService is a better choice.

JS: initiate search when fill input with script

I am trying to transfer the music list from an app to Spotify.
I got an array of songs (like [Hold On To Me Placebo, Come Undone Placebo] etc.) and tried to automate the liking of songs in this way:
let inputField = document.getElementsByClassName('_2f8ed265fb69fb70c0c9afef329ae0b6-scss')[0];
let menu = document.querySelectorAll('react-contextmenu')[0];
let like = document.querySelectorAll('react-contextmenu-item')[1];
function addSong() {
for (song of arrOfSongs) {
inputField.value = song;
menu.click();
like.click();
inputField.value = '';
}
}
addSong();
There are 2 problems:
When the value is changed in the input field, the search doesn't work: the content on the page stays the same as before filling it;
Even if I type the name of some song by myself, it returns the values of menu and like variables as undefined.
Problem 1: it's unclear what you mean with "the search doesn't work: the content on the page stays the same as before filling it". If you mean the value of the input, this happens because you first put there a value of a song, then 2 rows later you clear it with the instruction inputField.value = ''; . If you remove that everything will be updated.
Problem 2, probably react-contextmenu and react-contextmenu-item are class names and the querySelectorAll function works with selectors (see here https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors ). In this case you should change the assignment to the menu and like variables in this way
let menu = document.querySelectorAll('.react-contextmenu')[0];
let like = document.querySelectorAll('.react-contextmenu-item')[1];
See this fiddle

Save and load full html select in cookie/localStorage

There have been previous questions surrounding this, however I want to know if its possible to save the whole configuration of the html select in a cookie/localStorage. By the whole configuration I mean all of the options that are currently in the select, and which option is selected.
And then load this configuration back from the cookie.
From previous questions, I currently save the select element using an onChange listener, which saves the element like:
$('#chosen-url').on("change", function () {
saveToBrowserCookies("settings_select", this);
});
function saveToBrowserCookies(key, value) {
document.cookie = key + "=" + value + "; path=/";
}
And then load the select like so (on initialization):
var savedSelect = getFromBrowserCookies("settings_select");
if (savedSelect) {
var select = document.getElementById("chosen-url");
select.value = savedSelect;
}
function getFromBrowserCookies(key) {
var cookies = {}
var all = document.cookie;
var value = null;
if (all === "") { return cookies }
else {
var list = all.split("; ");
for (var i = 0; i < list.length; i++) {
var cookie = list[i];
var p = cookie.indexOf("=");
var name = cookie.substring(0, p);
if (name == key) {
value = cookie.substring(p + 1);
break;
}
}
}
return value;
}
However this doesn't work.
You can save anything in storage or in cookie, as long as it is a string. So in your case I'd recommend:
Get all your select options and currently selected value and create
an object with structure that would be easy to understand.
Stringify this object to JSON form with JSON.stringify.
Save json string in cookie or in LS.
After reload, get saved json, read it with JSON.parse and take all needed information from the object.
Recreate select element and set its chosen value.
I think that controlling select input per se is outside of the scope of this question, especially because we don't know if you are programming in pure js or in some kind of framework. But there are many informations on how to control select inputs on the web, e.g. here you can find decent answers on "how to set select value programatically".
Edit: you edited your question, so I will also add something to my response. You are trying to save whole "this" as cookie. I am not a big fan of jquery, but I guess that "this" is not necessarily the selected value. It may be a whole DOM object or change event maybe. Try logging out "this" and see what it is. You need to save string in a cookie.
Also, check in developer tools if the cookie was saved.
Last but not least, using break in a for loop is questionable. You can try using list.find instead.

About a loop that creates dynamic buttons, but cannot give proper values [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript infamous Loop problem?
I am having a small issue, and it would be very nice if some of you could realize about what kind of logic is missing here, since I cannot seem to find it:
I have an array with the results of some previous operation. Let's say that the array is:
var results = [0, 1];
And then I have a bunch of code where I create some buttons, and inside a for loop I assign a different function to those buttons, depending on the position of the array. The problem is that for some reason, all the buttons created (two in this case) come out with the function assigned to the last value of the array (in this case, both would come out as one, instead of the first with 0 and the second with 1)
This is the code:
for (var i = 0; i < results.length; i++) {
var br2 = b.document.createElement("br");
var reslabel = b.document.createTextNode(Nom[results[i]].toString());
var card = document.createElement("input");
card.type = "button";
id = results[i]; // this is the problematic value.
card.onclick = newcard; // this function will use the above value.
card.value = "Show card";
divcontainer.appendChild(br2);
divcontainer.appendChild(reslabel);
divcontainer.appendChild(card);
}
As it is, this code produces as many buttons as elements in the array, each with its proper label (it retrieves labels from another array). Everything is totally fine. Then, I click the button. All the buttons should run the newcard function. That function needs the id variable, so in this case it should be:
First button: runs newcard using variable id with value 0
Second button: runs newcard using variable id with value 1
But both buttons run using id as 1... why is that?
It might be very simple, or maybe is just that in my timezone is pretty late already :-) Anyways, I would appreciate any comment. I am learning a lot around here...
Thanks!
Edit to add the definition of newcard:
function newcard() {
id = id;
var toerase = window.document.getElementById("oldcard");
toerase.innerHTML = "";
generate();
}
the function generate will generate some content using id. Nothing wrong with it, it generates the content fine, is just that id is always set to the last item in the array.
Your id is a global variable, and when the loop ends it is set to the last value on the array. When the event handler code runs and asks for the value of id, it will get that last value.
You need to create a closure to capture the current results[i] and pass it along (this is a very common pitfal, see Javascript infamous Loop problem?). Since newcard is very simple, and id is actually used in generate, you could modify generate to take the id as a parameter. Then you won't need newcard anymore, you can do this instead:
card.onclick = (function(id) {
return function() {
window.document.getElementById("oldcard").innerHTML = "";
generate(id);
};
}(results[i]));
What this does is define and immediately invoke a function that is passed the current results[i]. It returns another function, which will be your actual onclick handler. That function has access to the id parameter of the outer function (that's called a closure). On each iteration of the loop, a new closure will be created, trapping each separate id for its own use.
Before going on, a HUGE thank you to bfavaretto for explaining some scoping subtelties that totally escaped me. It seems that in addition to the problems you had, you were also suffering from scoping, which bit me while I was trying to craft an answer.
Anyway, here's an example that works. I'm using forEach, which may not be supported on some browsers. However it does get around some of the scoping nastiness that was giving you grief:
<html>
<body>
<script>
var results = [0,1];
results.forEach( function(result) {
var card = document.createElement("input");
card.type = "button";
card.onclick = function() {
newcard( result );
}
card.value = "Show card";
document.body.appendChild(card);
});
function newcard(x) {
alert(x);
}
</script>
</body>
</html>
If you decide to stick with a traditional loop, please see bfavaretto's answer.

How can I implement a 'select all' check-box on my CRM 4 custom form?

I am working on a custom CRM form with numerous checkboxes, organized by sections. I would like to implement a 'select all' feature to the form and am trying to understand how to format the JavaScript. My research thus far has pointed me to the possibility of using a FOR statement to iterate through all of the elements in the section I want to process, setting their values accordingly, but am unsure of which document.getElements ... method to utilize.
Here is an existing SO question related to the FOR iteration I mention above:
How do I get all elements of a particular HTML tag in javascript?
I'm not sure I know what Tag Name I need to reference for my fields, using that method. They are of type BIT, is that the same as the Tag Name? I have exported the entity's customization file and have access to the class ID for the group of fields, is there a method I could use, passing that data?
in your crm form select change proterties for the 'select all' checkbox and add the following to the on change method
crmForm.all.[one of my checkboxen].DataValue = crmform.all.[my select all box].DataValue;
replace [one of my checkboxen] with the name of a checkbox (probably new_something) and [my select all box] with the name of your select all box.
add one line for each checkbox you want to control.
this is not an ideal solution as you have to keep updating the code everytime you add ot remove a check box but it has the adaventage that it works.
I figured it out; by utilizing the DOM through JavaScript, I was able to iterate through the checkbox items in my form section.
var section = document.getElementById("{5d86cfd1-4612-e211-8c63-0015c5f7fc75}");
var fields = section.getElementsByTagName("input");
if (crmForm.all.tmi_selectallwtm.DataValue == true) {
for (i = 0; i < fields.length; i++) {
if (fields[i].className == "ms-crm-CheckBox") {
fields[i].DataValue = true;
}//end IF
else {}
}//end FOR
}//end IF
else {
for (i = 0; i < fields.length; i++) {
if (fields[i].className == "ms-crm-CheckBox") {
fields[i].DataValue = false;
}//end IF
else {}
}//end FOR
}//end ELSE
var section = document.getElementById('a');
var fields = section.getElementsByTagName("input");
for (i = 0; i < fields.length; i++) {
fields[i].checked= true;
}

Categories

Resources