Formatting the values of variables in apps

Started by JohnZeman, August 09, 2017, 01:02:46 AM

Previous topic - Next topic

JohnZeman

Can the value of variables be formatted in apps like they could be in an app for IMatch 5?

In one of my IMatch 5 apps the following tag would displayed the date in long format that an image was taken.

{File.DateTime|format:XLDL;prefix:;postfix:}

But that doesn't seem to work in 2017 apps or am I doing something wrong?

Mario

The /variables endpoint and the /files endpoint with the var* fields use the same variable processor as IMatch.

I've made a test using

{File.DateTime|format:XLDL;prefix:abc;postfix:def}

with both endpoints and I get results like

"abcSonntag, 19. Juni 2016def"

which looks OK.

What are you doing, precisely. Which endpoints do you use and how?
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman

Apparently that's my problem.  I don't understand how to use an endpoint to format a variable.  I've spent two days scouring the help and sample files but haven't found the information I need or an example of how to do this.  Of course I'm probably overlooking something obvious.

All I know right now is the way I did it in version 5 doesn't work in 2017.  :-[

Mario

Do you use the /variables endpoint?
(Note: There is a bug in /variables in the current version which makes it return only one file record, even if you request 10 files. This has been fixed for next release.).

/variables allows you to parse/eval a variable for one or more files:


IMWS.get('v1/variables',{
    var: '{File.DateTime|format:XLDL;prefix:abc;postfix:def}',
    id: '1-10'
}).then(function(response) {
...


You can also request variables with the /files endpoint, e.g. when you also need other info about a file:


IMWS.get('v1/files',{
    id: '1-10',
    fields: 'id,filename',
    varTest: '{File.DateTime|format:XLDL;prefix:abc;postfix:def}'
}).then(function(response) {


The variable content is returned in the response in the element 'Test' (the name you specify after the var prefix). or, using an idlist:


IMWS.get('v1/files',{
    idlist: IMatch.idlist.fileWindowFocusedFile,
    fields: 'id,filename',
    varTest: '{File.DateTime|format:XLDL;prefix:abc;postfix:def}'
}).then(function(response) {

-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman

Thanks for this Mario, hopefully what you just posted here will get me over the hump.

I won't know for a while though because we're about to leave town for several hours.

Mario

Great. Let me know when you get stuck again.
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman

Thanks for your help Mario but it didn't take me long to get stuck again.  Your third example looks like it would work the best for my needs this time, and I do get the results I want when I look at the console log.  However my understanding from what you say, and from what it says in the IMatch documentation for the files endpoint section about VARS, is the result is assigned to a variable.  Which in your third example is named Test.

Essentially my question this time is How do I assign that value in the variable "Test" to an html element?  Thanks. :)

// begin test //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IMWS.get('v1/files',{
    idlist: IMatch.idlist.fileWindowFocusedFile,
    fields: 'id,filename',
    varTest: '{File.DateTime|format:XLDL;prefix:;postfix:}'
}).then(function(response) {
console.log(JSON.stringify(response));
// console.log(JSON.stringify(response,null,2));
});
// end test ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Jingo

Quote from: JohnZeman on August 09, 2017, 11:50:54 PM

Essentially my question this time is How do I assign that value in the variable "Test" to an html element?  Thanks. :)

// begin test //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
IMWS.get('v1/files',{
    idlist: IMatch.idlist.fileWindowFocusedFile,
    fields: 'id,filename',
    varTest: '{File.DateTime|format:XLDL;prefix:;postfix:}'
}).then(function(response) {
console.log(JSON.stringify(response));
// console.log(JSON.stringify(response,null,2));
});
// end test ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


You could do it using the following type of code (assume the text element is defined as: <td width="20" align="left" bgcolor="#048157" id="findnum"></td>)

              document.getElementById('findnum').innerHTML = response.files[0].Test;

JohnZeman

THANK YOU ANDY!!!
That was the piece of the puzzle I've been missing!!!

Little by little I've been gaining some confidence in creating apps here.  HTML and CSS I'm familiar with but I'm still a total noob at the JavaScript side of it, especially all this server stuff.  However now I believe I can finish converting my old collapsible metadata viewer app from version 5 to version 2017.  Everything else seems to be working in that app now, just need to purty it up a bit before I make it available to anyone else who might be interested in it.

Thanks again!  You wouldn't believe how much of my hair I've pulled out trying to figure this out!
And I really don't have all that much hair left to pull out. lol

Jingo

My pleasure John... I'm a complete Javascript newb too... only 2 months under my belt now.. thanks to the internet, I've been able to find and learn just about everything I've wanted to... and then just try to figure out how it all fits into IMWS...  Must admit - I'm completely loving Javascript and how I can very quickly create an app that links into IMatch... we've never had such power before.. and being able to do things OUTSIDE of the main IMatch app but still having access to the raw catalog data... that's been my overall dream for so many years.  IMatch Anywhere pretty much fits the bill of browsing my catalog with family and friends on my big screen TV - but the possibilities are pretty endless!

By the way - as Mario pointed out in another string - that code can probably be fancied up using JQuery which accesses the HTML elements much more elegantly (and perhaps more quickly if the code is complex) - its on my list to learn more about next month.

Good luck with your app... please let me know if I can help in any way! - Andy.

sinus

Quote from: JohnZeman on August 10, 2017, 01:59:33 AM
Thanks again!  You wouldn't believe how much of my hair I've pulled out trying to figure this out!
And I really don't have all that much hair left to pull out. lol

I believe you, John!  ;D
I am far away of your (limited, as you say) knowledge of JS. But only find a small thing takes me hours over hours, days over days.
And then comes another one here on the forum (like Andy, Thorsten and of course Mario) and solves it in no-time.

Impressive.
Best wishes from Switzerland! :-)
Markus

Mario

#11
Quote from: JohnZeman on August 10, 2017, 01:59:33 AM
That was the piece of the puzzle I've been missing!!!

In general, if you create an element in your HTML, give it an id. For example:

<p id="my-test"></p>

Then it is super-easy to set the value of the HTML element via jQuery, like so:

$('#my-test").text('This is the text I want to show in the paragraph'):

The blue part is an jQuery selector which selects the element with the id my-test.
text() sets or reads the text of an element.

This also works with <div id="bla"></div> or <span id="boo"></span> or when you work with tables it also works with <td id="col-1"></td>.

jQuery also makes it easy to append new HTML elements at runtime, e.g. when you dynamically build a table from the data you have received from IMWS.
The HTML Report sample app shows how to do this, for example.

jQuery provides a small but extremely powerful set of methods to manipulate the DOM (HTML). I highly recommend to read the w3schools jQuery tutorials which are interactive and let you try out things immediately: https://www.w3schools.com/jquery/jquery_dom_set.asp
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman

Thanks Markus, and thanks for this Mario.  What really had me stumped yesterday wasn't setting the value of an html element, it's was obtaining the value of the variable Test so I could set the html element value.  I spent hours searching and reading, and mostly concentrated on trying to parse the JSON result to get the value.  And then fortunately for me I happened to look back into this forum and saw Andy's solution then all of a sudden the lights came on for me. :)

I've filed this, and your method of using jQuery to set the value, away for future reference.  As a side note, I do spend a lot of time researching the information in w3chools and I agree it's a very good source.

Mario

The beauty of returning JSON data from web services is that JSON is the native format in which JavaScript holds objects.
Each JSON reply from IMWS is thus immediately a JavaScript object, which makes it very easy to process. IMWS does most of the work already.
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman


The line below used to work in IMatch 5 to replace the | character with > and to replace the ; charater that separates keywords with <br>

{File.MD.XMP::Lightroom\\hierarchicalSubject\\HierarchicalSubject\\0|replace:'==´;pereplace:|== > ;pereplace:~;==<br><br>}

And it partially works in 2017 except I haven't been able to successfully replace the ; character separating the keywords with a <br> line break.

{File.MD.XMP::Lightroom\\hierarchicalSubject\\HierarchicalSubject\\0\|replace\:\'\=\=´;pereplace\:~;\=\=\<br\>;pereplace\:\|\=\= \> }

Anyone see what I'm doing wrong here?  I'm doing this in an app mentioned above here.

thrinn

#15
John,
I am not very familiar with preplace, so I would try another approach:
Get only the variable value from IMWS.get, then make the necessary conversions in JavaScript. For example, vTest should contain what you need:

            // begin test //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            IMWS.get('v1/files', {
                idlist: IMatch.idlist.fileWindowFocusedFile,
                fields: 'id,filename',
                varTest: '{File.MD.XMP::Lightroom\\hierarchicalSubject\\HierarchicalSubject\\0}'
            }).then(response => {
                console.log(JSON.stringify(response));
                let vTest = response.files[0].Test.replace(/\|/g, '>').replace(/;/g, '<br>');
                console.log(vTest);
            }).catch(err => {
                console.log(JSON.stringify(response));
            })
            // end test ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

For explanation:

  • replace replaces a RegEx (first argument) with a string.
  • In JS, you can write regular expressions simply between /.../. I want to replace '|' with '>', so the first argument to replace has to be somenthing like /|/. But because '|' has es special meaning in regexp, I have to escape it with a backslash.
  • Then, I want to replace all occurrences of '|', not only the first one. I can do this by adding a 'g' flag (for global) to the regexp. So the resulting regexp is /\|/g.
  • The second argument to replace is simply the replacement string, '>' in this case.
  • Because the result of replace is again a string, I can just add another one to replace all occurrences of ';' with '<br>'.

The variable parser in IMatch is pretty powerful, but in an App you have all possibilities the language itself offers. So sometimes one only has to "think different". ;)
Thorsten
Win 10 / 64, IMatch 2018, IMA

Mario

This looks too complicated or me. Why bother with variables at all?
Getting the keywords of a file is easy via the tag* or /metadata endpoint.
Both deliver the keywords of your file(s) as a simple JavaScript array. Then format them as you with and present them in your app.
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

sinus

#17
John, maybe I understand not fully, what you want.
For me this variable works in VarToy:

{File.MD.XMP::Lightroom\hierarchicalSubject\HierarchicalSubject\0|pereplace:~;==<br><br>;pereplace:|==>}

Best wishes from Switzerland! :-)
Markus

Mario

I should have given an example for how to retrieve keywords from IMWS. Using a variable is really a clumsy approach here, especially when you also need lots of formatting to replace the ; list separator with <br/> to make each keyword wrap into a new line. Really clumsy.

The following code fragment fetches the keywords for the focused file.

My code then:

a) dumps them to the console.

b) Appends a <br/> to each keyword

c) Shows how to dynamically add the keywords to an <ul> list element.  This automatically puts each keyword into a separate row.

I just attach a screen shot of my editor because the syntax highlighting makes this easier to follow. This should give you some code to try. Excuse the spelling in the comments, I'm in a hurry.

-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman

Many thanks for this Mario.  I just now checked back into the forum here to tell Thorsten his solution worked, and in the process it taught this old dog something new.  I modified his suggestion to also replace & with &amp; for keywords that have a & in the name.

But before I go any further I'm going to see how Mario's suggestion works.

Markus you're right, your suggestion displays fine in the var toy, but it won't work in JavaScript without several characters being escaped.  That's what I was trying to do when I posted my question up above, only some of the replacements were working.

So thanks Thorsten, Mario, and Markus, now I'm going to see how much trouble I can get myself in by changing my app again.  :o

Mario

Very well. I recommend my sample above, because it will move you from BASIC thinking to modern programming more quickly. Chances are that you need more info for each file than just the keywords, and in that case you can just add more fields (I request only the id in my example) or tags in a single endpoint call, for any number of files!
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman

Suuhhhhweet!!

It works beautifully Mario, thank you!  The only extra thing I did was to add one additional line to replace "|" with " > " for better visibility in my app. :)

Now I can start wrapping this project up. :)


Mario

#22
See? Easy if you know how to do it.

Another idea:

When you replace each | with a span instead:

<span class="kw-sep"> | </span>

you can change the color, font, font-width or whatever of each | in your style sheet, depending on how you define the CSS class "kw-sep":

In the <head> of your index.html or in a separate .css file:

.kw-sep {
    font-weight: bold;
    color: #FFA201;
}

The above displays each | in bold and with an orange color.

Or, for fun, wrap each keyword in a

<span class="badge">KEYWORD HERE</span>

just to see how it looks. This is a Bootstrap class that makes each keyword a small "badge", which is what I use in IMatch WebViewer.
-- Mario
IMatch Developer
Forum Administrator
http://www.photools.com  -  Contact & Support - Follow me on 𝕏 - Like photools.com on Facebook

JohnZeman

Well easy isn't exactly the word I'd use but it works! :)  I like your suggestion to format the keyword separator, and I tried the badge too but went back to just using a different color for the separator.

Thanks so much again Mario, you've had a huge impact on the way this app has evolved. :)

I've finished it now and will make the app available in another thread.