I want to Change the value assigned to a Document Property in spot fire. Lets say i have created a new document property called "Test1" as a string and assign it a value "a". Is there are way to change this value using Javascript every time i load the spotfire dashboard ?
I'm unaware of a way to use JavaScript for this, but you can assign a string document property via custom expression (if it's a List Box) or run an IronPython script each time the value changes. So, you could set the expression to the current date, datetimenow() and then every time it's loaded the IronPython script would fire. However, I don't see why you'd need the property control for this.
I suppose it really depends on what you want the document property to be set to. Is it data from your tables? Output from complex code? These are all things to consider.
1) Create an input type property control using the Document Property you want to change.
2) Edit Html to assign parent element an id say "testInput". And add the script as shown below in the Edit HTML window.
<span id="testInput"><SpotfireControl id="7db34e6c423240f59fc99e6b80fa23ec" /></span>
<script>
$("#testInput input").val("after");
$("#testInput input").focus();
$("#testInput input").blur();
</script>
3) This script will change the document property value to "after" whenever you open a file.
As you comment seemed to suggest, something you can do is write this code in Python and attach the script to an action control, e.i. a Link or a Button. Something simple like: Document.Properties["Test1"] = newValue
or even: Document.Properties[changingProperty] = newValue
allowing the code to be more reusable.
Then you insert Javascript into the Text Area as well to the effect of: $("#VeryLongSpotfireControlID").click();
Which should simulate clicking on action control, which in turn triggers the Python script to update the value. Just be careful not to use this approach when it would result in reloading the text area HTML, as this will re-trigger the Javascript, thus creating an endless loop.
I believe I have found a possible solution/work-around for the issue, entirely based on pure JavaScript (since TIBCO removed jQuery starting from Spotfire X). The solution is to force a simulated Enter Keystroke while focusing the input box to trigger updating the Document Property. (No data function and R needed)
HTML (SpotfireControl Element is an single line input-box for a Doc. Prop.):
<div id="container"><SpotfireControl id="b8534f13dc62416db6d4eaab16030f5e" /></div>
JS (focus and blur might no longer be needed for this solution, but I'm still keeping them just in case):
const inputConfirmationEvent = new KeyboardEvent("keypress", {
keyCode: 13,
bubbles: true,
cancelable: false
});
var elem = document.querySelector("#container input");
elem.value = "stringValue";
elem.blur();
elem.focus();
document.querySelector("#container input").dispatchEvent(inputConfirmationEvent);
Hope it helps someone.
Best,
Aaron
Related
First of all, I am not a programmer. I do not know Javascript at all. I'm trying to create a Chrome extension that modifies my browser tab's title, by taking a specific string on a webpage. I know how to create Chrome extensions (just barely) and I just need to modify the Javascript to do what I want (which I do not know how).
I found the following script online and am trying to modify it but can't figure out how to get it working. Here is the script:
https://pastebin.com/dY1LSdjT
// Fire this event any time the mouse is moving. Sucks for performance, but it's a better experience
document.addEventListener("mousemove", function() {
// This will get us the banner
let bannerTextElements = document.getElementsByClassName("dijitReset dijitInputField dijitInputContainer");
console.log(bannerTextElements);
console.log(bannerTextElements[0]);
if (bannerTextElements[0]) {
console.log("ok!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
console.log(bannerTextElements[0].innerHTML);
// This will get us the text
let bannerTextLine = bannerTextElements[0].getElementsByClassName("dijitReset dijitInputInner");
console.log(bannerTextLine);
document.title = bannerTextLine[0].innerHTML
}
}, false);
And here's the website viewed in developer mode. I would like to get the text "blahhhh" and use that for the title of my browser tab.
Below is a different webpage and the difference here is that the "div class" names will change. The numbers in those class will change to different numbers, but the structure and the overall name remains the same. For example, "ms-Button-label label-549" may change to "ms-Button-label label-640". This happens whenever you refresh the page. I found that the "viewport" id name doesn't change though, so I think if we can use that as a reference and then just look at the nested div classes and reference them and extract the value (in this case Crystal Mountain).
Fixing your code
You got like 95% of everything you need.
The one thing you are missing right now is that the fact that an input element does not posses an "innerHTML" (That is why it isn't closed like this: <input>renderedText</input>). Instead you want to check for it's value:
document.title = bannerTextLine[0].value;
Some Improvements:
Search by ID
You have a well defined input which can be more easily obtained by looking it up using the id:
let bannerTextLine = document.getElementById('lanDeviceIndex_searchBox');
End result:
const bannerTextLine = document.getElementById('lanDeviceIndex_searchBox');
bannerTextLine.addEventListener("blur", function() {
if (bannerTextLine != null) {
document.title = bannerTextLine.value;
}
});
This is the entire JS code. Note that I changed the event to blur which activates when the form is left, this should be optimal for your case.
1: What I want to do is check if a page contains a specific class with a specific string, and if it does, send an event to Google Tag Manager.
2: I also need a macro to check if a certain element exists on a page and if it does, fire the tag above.
What I have been able to get together so far is the supposed tag:
<html>
<head></head>
<body>
...
<a class="myClass">Captured value</a>
...
</body>
</html>
My tag to be fired using JavaScript would look something like this:
<script>
var x = document.getElementsByClassName("myClass")[0].innerHTML;
if (x.match ("Captured value")) {
dataLayer.push({'event':'captured'});
}
</script>
So this tag will fire if it sees the above anchor with that specific class. Using the above code though, I keep getting errors:
Uncaught Type Error: Cannot read property 'innerHTML' of undefined(anonymous function)
#VM490:2InjectedScript._evaluateOn
#VM479:883InjectedScript._evaluateAndWrap
#VM479:816InjectedScript.evaluate
#VM479:682
How would I write a cleaner code to not generate an error if the class doesn't exist?
Regarding number two, how would I write a function with a return statement? I just can't figure this one out. I have tried something along the lines of:
function () {
var t = document.getElementsByClassName("myClass")[0].innerHTML;
var y = dataLayer.push({'event':'trigger'})
if (t.match ("Captured value")) {
return y;
}
I want to use a macro to check if the class exists on a page with the correct value, which in turn I can use as a trigger to fire the first tag. To use macros in GTM, I need to return a value. I just can't figure out how to check for the class value and have my tag fire upon its validation.
Another way to go is of course to write a custom HTML tag to fire on all pages and have the JavaScript look for, validate and send the event. I currently do not possess the JavaScript aptitude to figure out how that would look though.
Any suggestions are highly appreciated.
With your second block of code, I would first make it a self-invoking function
<script>
(function(){
...
}()
</script>
that checkes for the presence of the class in question and also checks for the required text. Use 'indexOf' rather than 'matches' (so you do not need to deal with regex). If those two conditions are true, then push your event to the dataLayer. Fire this tag when event equals gtm.dom, along with any other conditions you think should apply, and that should do it.
Google Tag Manager has a perfectly usable DOM element variable for this. Go to variables (assuming GTM v2), "new", "DOM Element", Selection Method "CSS selector", selector ".myClass" (from your example).
Set up a trigger "page view", trigger type "DOM ready", fire on "yourDOMelement eq. "Captured value".
Unless I misunderstand your needs you should not havbe to write any custom javascript.
My approach was all backwards. I attempted to use a JavaScript solution while I could just use a custom JS inside of Tag Manager to check for a defined value and fire a trigger if it resolved to true.
The methodology I was thinking about was about right I guess, but the way about doing it was over complicating things.
What I did was add a custom JavaScript macro named cjs.return class (using v1 for this said container) and added the following code:
function (){
x = document.getElementsByClassName("myClass")[0].innerHTML;
return x;
}
This function returned either undefined or "Captured value" depending on if it was the right page or not. I then set up a new rule to trigger my tag if:
event equals gtm.dom
cjs.return class equals Captured value
This new rule triggered my tag, which in turn could send the data on the specific set of pages I wanted it to fire on.
Thanks to both Eike and nyuen for answering to give me a clearer picture of what I did wrong.
I am trying to capture HTML text value using jQuery in custom script of DTM data element.
See the scenario:
Below is the snippet of code on the page:
<div class="site-categories">
<ul>
<li class="mobile-tablets main">
Mobiles & Tablets
Computers
Electronics
and so on.
So basically the ask is to capture the inner HTML text of anchor tag i.e. 'Mobiles & Tablets' or 'Computers' or 'Electronics', depending upon on what link, user clicks.
To achieve this, in the event based rule section, I have set Condition as the tag to fire when class (under div tag) equals 'site-categories' and enabled bubbling on child elements (so as to cover everything under this to fire omniture tag). And then assigning the value of data element in any evar variable.
In the data element section, after selecting the custom script option, I am writing this code:
var value = $('this').html();
return value;
or
var value = jQuery('this').html();
return value;
But this is not working. I even tried using this:
var value;
_satellite.setVar('value', jQuery('this').html());
return value;
But this also didn't worked. Can I have a solution for this ? I want this to be dynamic as in, depending upon which section user is clicking on the page, the data element should capture the inner HTML text of that particular anchor tag.
Not sure where I am going wrong.
If there is any other solution that exist for this, please let me know. That would be a great help.
Thanks in advance,
Adi
Couple of notes:
Firstly on a sidenote, in your jQuery code, this should not be wrapped in quotes. You should be passing an object reference to the jQuery wrapper. Wrapping it in quotes makes it look for an html element called "this" (e.g. <this>foobar</this>) which is not right.
As to your issue.. not sure how you have setup your rule but basically what you want to do is grab the value and put it into a data element, and then reference the data element when you set the Adobe Analytics variable. So it looks like you were on the right track, and BrettAHale's answer is on the right track too, but to put it all together:
In your rule, add a condition with criteria Data > Custom. Then click "add criteria" and in the codebox, enter in:
_satellite.setVar('linkText', jQuery(this).text());
return true;
This will set a data element named "linkText", and you return true to make sure the condition is always true. You can use "value" as the name but you should use something more descriptive so you can more easily remember it's purpose later (I used "linkText").
Then, in your Adobe Analytics section of the rule, go to the eVars section and select the eVar you want to set. Then for the "set as" value, enter in %linkText%. This is a reference to the data element you just set in the rule. Don't worry if DTM shows a tooltip saying not found or w/e; it only shows/searches for known data elements you set in the interface, not on-the-fly in rules. Click the "save evar" button and you should see e.g. eVar3="%linkText%" listed (but for whatever eVar you chose).
Save and then test/publish the rule.
In the analytics tool section or your rule, set the eVar using the following, not a data element.
%this.text%
Your evar box will show something like this. eVarX="%this.text%"
I have a problem to set an attribute on another element.
I'm using PHP code with JS and HTML and it looks like:
<textarea name='$id' id='$id' class='regular-text' cols='60' rows='1' tabindex='2'"
. "onkeypress =\"javascript:document.getElementById('content').setAttribute('onkeypress', document.getElementById('so_observer_heading_count').innerHTML = document.getElementById('content').value.length)\">$value</textarea>
You must know I have 2 elements. The first('content') one I use for writing a text and in the other one('so_observer_heading_count') there shall be updated the number of signs from the first element.
So my question is, how can I set an attribute on another element.
I have already checked that the name is correct and when i change the content of the textarea on the 2. element I get the right amount from the first element. But I want only to change content in the first element to refresh the amount.
And I don't want to change the code of the first element! And don't be confused by the textarea, in future this shall be a label or something else.
First of all:
Don't use the inline-eventbindings. Always use "real" javascript, (this way you also prevent the problem of escaping your quotes) this is far more cleaner and more maintanable.
Also you code has another problem: You have an eventhandler "keypress" on the textarea, which binds on every "keypress" another attribute to your content-element. This is not very performant and most likey won't work properly. This code should be everything you need:
document.getElementById('content').addEventListener("keyup",function(){
var obs = document.getElementById('so_observer_heading_count');
obs.innerHTML = this.value.length;
});
Here is a demo for you.
Edit: I changed the event from keypress to keyup to 1) count properly 2) take charakter deletion into account.
I'd say "setAttribute" won't work on a method. Try instead :
document.getElementById('content').onkeypress = function() { document.getElementById('so_observer_heading_count').innerHTML = document.getElementById('content').value.length };
Well, there are certainly more.. efficient ways of doing this, but the thing you forgot to do was escape your single quotes, so the js treats your event as a string, instead of parsing the end result:
<textarea name='$id' id='$id' class='regular-text' cols='60' rows='1' tabindex='2'"
. "onkeypress =\"document.getElementById('content').setAttribute('onkeypress', 'document.getElementById(\'so_observer_heading_count\').innerHTML = document.getElementById(\'content\').value.length;')\">$value</textarea>
Elsewise.. I would personally do this through an included js file that executes the above line on document load/ready, versus every time a key is pressed.
Update: slight edit so anything I removed from your above code was added back, incase you want to just straight-copy it in.
I use TEmbeddedWebBrowser to fill a html form using FillForm method. But my html form contains a fully javascript based editor and i don't know how to fill that.
Something like this :
your comment :
<script type='text/javascript' src='public/scripts/src/editor.js?1'></script>
And the submit btton :
<input type="submit" name="btnSubmit" id="btnSubmit" value="Send" class="btn" onclick="rtevalue("data[body]",437934);" />
The editor itself is a DIV (could be other HTML element) or IFRAME set to contentEditable / designMode = on.
If the element is a DIVyou could use it's InnerHTML property.
For the best results with an IFRAME use the below code:
procedure TForm1.Button1Click(Sender: TObject);
var
editorDoc: OleVariant;
range: OleVariant;
id: OleVariant;
begin
id := 'editor'; // frame ID
editorDoc := (WebBrowser1.Document as IHTMLDocument2).parentWindow.frames.item(id).Document;
range := editorDoc.body.createTextRange();
// range.collapse(false); // if you need to append
range.select();
range.pasteHTML('<b>Boo!</b>');
end;
Notes:
No error checking to simplify the code.
You might also try range.execCommand('inserthtml', false, MyText) (Not tested with TEmbeddedWebBrowser, but had bogus results when I tried it with plain HTML/Javascript on IE).
I have no experience concerning this TEmbeddedWebBrowser tool, but according to your post I'm thinking of a way to retrieve the form's fields. Once you know what fields it contains, I suppose you can fill them as it doesn't seem to be the purpose of your post.
Assuming there is a form declared and it is reachable: you can grab the form and
parse its .elements collection: easily if it's declared in your page
(give it an id attribute, then use a document.getElementById()),
it may still be doable if the form is declared by/inside
editor.js, using document.forms then.
Otherwise: you can get a dump
script from the Net - like this one -
and see what is printed when you call (after including editor.js
naturally) dump(data) or dump(data[body]). As data[] is
used as an argument to the rtevalue() called by your submit button's
onclick, it should contain the form's key/value pairs. The bad thing about this method is that data[] must
be filled by Javascript, so if your form has radio buttons or
checkboxes you may only see the selected ones, which is why I would give a shot at the first option before trying this trick.
About the comments, you should not directly use innerHTML to insert an HTML subtree to the document as most of the times it doesn't work (especially when forms are involved), have an appendChild() redo the work to ensure a correct document, like this:
var dummyContainer=document.createElement("span");
var dummyContainer.innerHTML="..."; //insert stuff here, because it's easy to use ;)
myContainer.innerHTML=""; //clearing your "real" container doesn't add anything to the HTML tree, it'll work - you can also use removeChild() in a loop (but it's not as easy to use!)
myContainer.appendChild(dummyContainer); //appendChild will translate properly the text inserted by innerHTML in dummyContainer into a clean HTML subtree