Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie
Hi there,
There is an issue with role permissions that is being worked on at the moment.
If you are having trouble with access or permissions on regional forums please post here to get access: https://www.boards.ie/discussion/2058365403/you-do-not-have-permission-for-that#latest

Static Website with a REST API

  • 26-03-2021 8:40pm
    #1
    Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭


    Hey guys,

    I've been working on backend stuff for most of my time and only occasionally looked at front end stuff so my knowledge in this area is really lacking.

    I'm trying to surprise someone with a gag present next week of a website that when they put in keywords into the text box on the site, it'll hit an API and return a block of text, then they reset the page back to starting point and try another keyword. Effectively a terrible digital treasure hunt. :D

    In my head I thought I could do this with bare bones HTML & CSS and maybe an odd line or two of javascript for the REST API part but after putting the page together, I'm realising I've underestimated the difficulty of the API integration and now while looking into options online, every page seems to mention a new tool. I'm not necessarily looking for help, but recommendations of what people would use in this case? Again, not professional, doesn't need to be reliable, it's a gag present I'm trying to learn a bit of front end coding with as well :)

    Put in a diagram as they reckon a picture paints 1000 words. As you can see I had thought it could be done with 2 separate webpages but not sure if I'm missing a trick with a dynamic frame or something on a single page site
    architecture.png

    Appreciate any insights or advice guys!


Comments

  • Registered Users, Registered Users 2 Posts: 1,704 ✭✭✭JoyPad


    RedXIV wrote: »
    In my head I thought I could do this with bare bones HTML & CSS and maybe an odd line or two of javascript for the REST API part[...]

    I haven't coded UI in a decade, but I think what you need is a simple page, with a bit of jQuery.
    I would create the page with both the windows, one visible (input), one hidden (response). This is your starting view.
    Handler for the Submit button will make the API call, placing the response in the hidden DIV, make it visible, and hide the input DIV. Now you have your response view.
    Handler for the Reset button just flips the visibility for the two DIVs again, returning to the input view.

    But, as I said, I haven't written JS in a long time :)


  • Registered Users, Registered Users 2 Posts: 9,383 ✭✭✭S.M.B.


    Sounds about right but no real need to use jQuery for any of that.

    I'm assuming your hunt for info online is suggesting using the likes of React or Vue which would be overkill but if you're keen to see the differences between doing this with vanilla JS and a modern framework then may be worth diving into.


  • Registered Users, Registered Users 2 Posts: 74 ✭✭terenurebob


    You just need to use XMLHttpRequest

    https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

    https://www.w3schools.com/xml/xml_http.asp

    There are some good examples there. If you search for XMLHttpRequest or AJAX, you will find lots of examples.

    You can also take a look at JQuery but for what you need, vanilla XMLHttpRequest and Javascript should suffice.

    If you post up the HTML you have now, it should only take a few minutes to provide working code.


  • Moderators, Recreation & Hobbies Moderators Posts: 11,912 Mod ✭✭✭✭igCorcaigh


    JoyPad wrote: »
    I haven't coded UI in a decade, but I think what you need is a simple page, with a bit of jQuery.
    I would create the page with both the windows, one visible (input), one hidden (response). This is your starting view.
    Handler for the Submit button will make the API call, placing the response in the hidden DIV, make it visible, and hide the input DIV. Now you have your response view.
    Handler for the Reset button just flips the visibility for the two DIVs again, returning to the input view.

    But, as I said, I haven't written JS in a long time :)

    I would go with this.
    Just toggle the visibility of the panels, so that it appears as if you have two different pages.

    You don't need jQuery to do this, but I would definitely recommend it if you want to learn.

    Otherwise, just use plain javascript:

    function Toggle(myDIV) {
    var x = document.getElementById(myDIV);
    if (x.style.display === "none") {
    x.style.display = "block";
    } else {
    x.style.display = "none";
    }
    }


  • Registered Users, Registered Users 2 Posts: 9,383 ✭✭✭S.M.B.


    The Fetch API has somewhat superseded XMLHttpRequest objects but either could be used for the API call.

    https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 10,912 ✭✭✭✭28064212


    It's not entirely clear from your opening post: is the API something that already exists, or are you building that as well? If it's the former, it should be pretty simple to use XMLHttpRequest or the Fetch API as already mentioned (XMLHttpRequest might be a little easier if you haven't used Promises in JavaScript before). If it's the latter, you've got quite a bit more work to flesh out

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭RedXIV


    S.M.B. wrote: »
    Sounds about right but no real need to use jQuery for any of that.

    I'm assuming your hunt for info online is suggesting using the likes of React or Vue which would be overkill but if you're keen to see the differences between doing this with vanilla JS and a modern framework then may be worth diving into.

    This was my problem exactly, everything I was looking up was suggesting a new JS framework rather than vanilla JS and I was more interested in the vanilla side as, seen in the evidence in the other posts, this is not a very complex piece of functionality.
    You just need to use XMLHttpRequest

    https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

    https://www.w3schools.com/xml/xml_http.asp

    There are some good examples there. If you search for XMLHttpRequest or AJAX, you will find lots of examples.

    You can also take a look at JQuery but for what you need, vanilla XMLHttpRequest and Javascript should suffice.

    If you post up the HTML you have now, it should only take a few minutes to provide working code.

    I was using this originally based on an example I was looking at from stackoverflow but for some reason it kept using the domain URL (i.e. localhost while dev is ongoing) instead of the target URL (I've a mocky one built for testing) and I couldn't figure out why as it looked like a straightforward call. I'm trying now to avoid stackoverflow and rebuild based on a good tutorial to see if this helps.
    igCorcaigh wrote: »
    I would go with this.
    Just toggle the visibility of the panels, so that it appears as if you have two different pages.

    You don't need jQuery to do this, but I would definitely recommend it if you want to learn.

    Otherwise, just use plain javascript:

    function Toggle(myDIV) {
    var x = document.getElementById(myDIV);
    if (x.style.display === "none") {
    x.style.display = "block";
    } else {
    x.style.display = "none";
    }
    }

    This has massively simplified what I was trying to do in terms of reloading pages, I wasn't aware you could set ".display" to none, so thank you!
    S.M.B. wrote: »
    The Fetch API has somewhat superseded XMLHttpRequest objects but either could be used for the API call.

    https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

    Cheers, this is what I've been looking at now. I know XMLHttpRequest seems to be the default but I'm hoping this being a little more recent will also make it user friendly.
    28064212 wrote: »
    It's not entirely clear from your opening post: is the API something that already exists, or are you building that as well? If it's the former, it should be pretty simple to use XMLHttpRequest or the Fetch API as already mentioned (XMLHttpRequest might be a little easier if you haven't used Promises in JavaScript before). If it's the latter, you've got quite a bit more work to flesh out

    I've to build the REST API myself but I've done that loads of times before using AWS components, I've no problems doing that part as it's been something I've done for day jobs and other small projects. I just never put a UI in front of it before :D


    Thanks again for all your help guys, I'm currently working on this example -> How to use and API with JavaScript which helps build from the ground up but if I'm not making progress with this in the next few hours, I'll throw up the code and I'll happily let people point out where my typo (or fundamental lack of understanding is). But really, again, I appreciate all the help here, I've learned loads already!


  • Registered Users, Registered Users 2 Posts: 5,863 ✭✭✭RobAMerc


    what you are describing is an SPA ( single Page Application ) , although a very simple one.
    Doing some research on this will help you understand what frameworks and tech you can use to achieve your goals.

    I'm not sure what tech stack you are using, but if you download a free copy of Visual Studio there are template applications scaffodling there that you could simply download and spin up in a matter of minutes. Then just customise it for you won needs.

    A free azure sub and an app service would allow you put the whole thing together and host it in hour or so.

    If you wish to keep going with your current app, remember you will possibly start to run into same origin policy issues potentially ( depending on how you've deployed it )

    hth


  • Moderators, Computer Games Moderators Posts: 4,282 Mod ✭✭✭✭deconduo


    RedXIV wrote: »
    This was my problem exactly, everything I was looking up was suggesting a new JS framework rather than vanilla JS and I was more interested in the vanilla side as, seen in the evidence in the other posts, this is not a very complex piece of functionality.



    I was using this originally based on an example I was looking at from stackoverflow but for some reason it kept using the domain URL (i.e. localhost while dev is ongoing) instead of the target URL (I've a mocky one built for testing) and I couldn't figure out why as it looked like a straightforward call. I'm trying now to avoid stackoverflow and rebuild based on a good tutorial to see if this helps.



    This has massively simplified what I was trying to do in terms of reloading pages, I wasn't aware you could set ".display" to none, so thank you!



    Cheers, this is what I've been looking at now. I know XMLHttpRequest seems to be the default but I'm hoping this being a little more recent will also make it user friendly.



    I've to build the REST API myself but I've done that loads of times before using AWS components, I've no problems doing that part as it's been something I've done for day jobs and other small projects. I just never put a UI in front of it before :D


    Thanks again for all your help guys, I'm currently working on this example -> How to use and API with JavaScript which helps build from the ground up but if I'm not making progress with this in the next few hours, I'll throw up the code and I'll happily let people point out where my typo (or fundamental lack of understanding is). But really, again, I appreciate all the help here, I've learned loads already!

    If you're working with AWS anyway I'd recommend looking at using Amplify for something like this in the future by the way. It's designed for serverless sites and super easy to use if you're comfortable with the AWS environment and services


  • Registered Users, Registered Users 2 Posts: 2,040 ✭✭✭Colonel Panic


    There's even a "vanilla javascript" Amplify example on their documentation that doesn't use any front end framework at all.


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 9,383 ✭✭✭S.M.B.


    I had never really bothered looking into Amplify before as I wasn't 100% sure what it was and while it seems potentially a little overkill for what the OP is trying to do if there's no intention to add to the site beyond the MVP, I am definitely going to look at it myself to quickly get a web app up and running. It looks like a really useful tool.


  • Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭RedXIV


    Guys I'm so close after multiple hours of trying:
    • Basic HTML/JS
    • Porting to React
    • Trying Amplify
    • Going back to vanilla HTML & JS

    The only thing I can't seem to figure out is now that I have the code doing pretty much what I want is that on loading the page, my inline javascript code in my <script> tags is executing with empty values. Is there a way to prevent the script tag from loading until the function is called explicitly in my button.onClick event?

    Or is this expected behaviour I need to adapt my JS for?

    Cheers!


  • Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭RedXIV


    I managed to put in a hack that checks for a variable used in the execution which the user needs to enter. It its null (i.e. if the app has just loaded), it will return out of the JS code as soon as it tries to execute.

    I-did-it_1.jpg


  • Registered Users, Registered Users 2 Posts: 10,912 ✭✭✭✭28064212


    RedXIV wrote: »
    The only thing I can't seem to figure out is now that I have the code doing pretty much what I want is that on loading the page, my inline javascript code in my <script> tags is executing with empty values. Is there a way to prevent the script tag from loading until the function is called explicitly in my button.onClick event?

    Or is this expected behaviour I need to adapt my JS for?
    Is your JS function explicitly declared? JS in a function doesn't execute unless called. You should have something like this:[html]<script>
    function myFunction() {
    //...
    }
    </script>[/html]and[html]<button onclick="myFunction()">Click me</button>[/html]

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭RedXIV


    28064212 wrote: »
    Is your JS function explicitly declared? JS in a function doesn't execute unless called. You should have something like this:[html]<script>
    function myFunction() {
    //...
    }
    </script>[/html]and[html]<button onclick="myFunction()">Click me</button>[/html]


    I think my problem was when I started using the fetch API, the documentation I was basing it off was looking for an "await" keyword and as a result the function was declared as
    async function myFunction()
    
    instead


  • Registered Users, Registered Users 2 Posts: 10,912 ✭✭✭✭28064212


    RedXIV wrote: »
    I think my problem was when I started using the fetch API, the documentation I was basing it off was looking for an "await" keyword and as a result the function was declared as
    async function myFunction()
    
    instead
    That shouldn't matter, the function still won't run until it's called. See this example: https://jsfiddle.net/r7kum60a/. The javascript in myFunc won't run until the button is clicked

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭RedXIV


    Is it possible because it was part of a <form> that could explain it?


  • Registered Users, Registered Users 2 Posts: 10,912 ✭✭✭✭28064212


    There's no inherent reason why it being part of a form would cause your code to run on page load

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭RedXIV


    Here's the code if there is something obvious at play:
    <html>
        <head>
            <titleTreasure Hunt!</title>
            <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width,initial-scale=1">
            
            <style>
    * {
      box-sizing: border-box;
    }
    
    /* Create two equal columns that floats next to each other */
    .column {
      float: left;
      width: 50%;
      padding: 10px;
      position: relative;
    
    }
    
    .columnChild {
      position: absolute;
      top: 50%;
      left: 50%;
      margin: -25px 0 0 -25px;            
     }
                
    /* Clear floats after the columns */
    .row:after {
      content: "";
      display: table;
      clear: both;
    }
    
    /* Responsive layout - makes the two columns stack on top of each other instead of next to each other */
    @media screen and (max-width: 600px) {
      .column {
        width: 100%;
      }
    }
    
    /* Use this to make response block disappear*/
    .invisible { display: none; }            
                
                
    </style>
            
        </head>
        <body>        
            
            <header class="w3-container w3-blue">
                <h1>Niall's activites for the day</h1>
            </header>
            
            <div class="row">
                <div class="column w3-border w3-border-blue">
                    <img src="images/profile.jpg" alt="who?" style="width:50%">
                </div>
                     
                <div class="column ">
                     <div class="w3-container w3-blue ">
                        <h2>Put the answer in when you get it!</h2>
                    </div>
    
                    <form class="w3-container" method="get" action="" onsubmit="event.preventDefault();">
                        <br>
                        <label class="w3-text-blue"><b>Answer</b></label>
                        <input class="w3-input w3-border w3-light-grey" type="text" name="answer" id="answer">
                        <br>
    
                        <button class="w3-btn w3-blue" onclick="getResponse()" >Submit</button>
                        <button class="w3-btn w3-blue" onclick="resetResponse()">Reset</button>
                    </form>
                    
                    <div class="w3-container invisible" id="response-div">
                        
                        <textarea 
                                  name="response" 
                                  id="response" 
                                  placeholder="Response will appear here"
                                  cols="40"
                        >
                        </textarea>
                            
                    </div>
                    
                </div>
            </div>
                    
            
           <footer class="w3-container w3-blue w3-border w3-border-blue">
                <h5>** Not taking responsibility of any offense taken </h5>
           </footer>
            
            
            <script type="text/javascript">
                async function getResponse(){
                    console.log("starting API Request")
                    submittedAnswer = document.getElementById('answer').value
                    if (!submittedAnswer || submittedAnswer .length === 0){
                        console.log("stopping flow")
                        return false;
                    }
                    console.log(submittedAnswer )
                    API_URL = 'my-big-durty-url';
    
                    const response = await fetch(API_URL, {
                        method: "GET",
                        mode: "cors",
                        headers: {
                            'submittedAnswer': submittedAnswer 
                            },
                        }
                    )
                    .then(response => response.json())
                    .then(data => {
                        console.log('data is', data)
                        responseText = data.messageToUser;
                        console.log(responseText)
                        setResponse(responseText)
                    })
    
                    
                }
    
                getResponse()
    
                function setResponse(responseText = ''){
                        const responseBlockElement = document.getElementById('response-div');
                        responseBlockElement.classList.remove('invisible');
        
                        const responseElement = document.getElementById('response');
        
                        responseElement.textContent = responseText;
                    
                        //resizing text area
                        const tx = document.getElementsByTagName("textarea");
                        for (let i = 0; i < tx.length; i++) {
                            tx[i].setAttribute("style", "height:" + (tx[i].scrollHeight) + "px;overflow-y:hidden;");
                            tx[i].addEventListener("input", OnInput, false);
                        }
                }
                
                function OnInput() {
                        this.style.height = "auto";
                        this.style.height = (this.scrollHeight) + "px";   
                }
                
                
                function resetResponse(){
                        const responseBlockElement = document.getElementById('response-div');
                        responseBlockElement.classList.add('invisible');
                }
                
            </script>
    
        </body>
    </html>
    


  • Registered Users, Registered Users 2 Posts: 10,912 ✭✭✭✭28064212


    You're calling getResponse() manually on line 127

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Advertisement
  • Registered Users, Registered Users 2 Posts: 8,493 ✭✭✭RedXIV


    28064212 wrote: »
    You're calling getResponse() manually on line 127

    ..............excuse me while I go die quietly in a pit somewhere. :D

    No idea how I kept missing that.

    Thanks for taking the time to look!


Advertisement