DELETE Request Failing on API with Frontend, but Works in Main App and Postman [closed]

I’m working on an application with a separate frontend that interacts with an API to return data to a specific table. The index functionality is working fine, but I’m having trouble with the DELETE request.

When I try to delete a record using the frontend, I receive an error in the Network tab of the browser’s developer tools. However, the delete operation works perfectly when performed in the main application and also when tested using Postman.

[enter image description here](https://i.sstatic.net/xVLevsiI.png)

I added some lines to the nginx settings file as suggested by various solutions to resolve the issue, but unfortunately, it didn’t make any difference.

How can I fix PHP pages overlapping

I’m encountering an issue with file conflicts between different pages on my website. Specifically, when a user logs in and is redirected to their dashboard, the content from the login page, including CSS and HTML elements, is appearing on the dashboard page.

I’ve implemented PHP sessions to handle user authentication and have created separate files for session management (session_handler.php) and authentication (tauth.php) “for teacher login”. However, it seems like the session data or file inclusion mechanisms are causing the issue.

Note:
I have to include these files in each page to authenticate user data as he uses the website in this way:

<?php
require_once 'session_handler.php';
require_once 'tauth.php';

$conn = getDatabaseConnection();
?>

I use “require_once” for not to repeat including files in the page many times.

Possible causes I’m considering:

  • Connection with Database must be closed after successful login.
  • Issues with storing session data.
  • Invalid PHP functions may cause conflicts between pages files.

login.php:

<?php
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1);
ini_set('session.use_strict_mode', 1);

require 'session_handler.php';

$errors = [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
        $errors[] = 'Ivalid CSRF token.';
    } else {
        $username = htmlspecialchars(trim(mysqli_real_escape_string($conn, $_POST['username'])));
        $password = htmlspecialchars($_POST['password']);
        $account_type = htmlspecialchars($_POST['account_type']);

        if (!in_array($account_type, ['teacher', 'student'])) {
            $errors[] = 'Incorrect Account Type.';
        }

        if (empty($username)) {
            $errors[] = 'Please Enter Username.';
        }
        if (empty($password)) {
            $errors[] = 'Please Enter Password.';
        }

        if (empty($errors)) {
            $table = ($account_type === 'teacher') ? 'teacher' : 'student';
            $query = "SELECT * FROM $table WHERE username = ?";
            if ($stmt = $conn->prepare($query)) {
                $stmt->bind_param("s", $username);
                $stmt->execute();
                $result = $stmt->get_result();

                if ($result->num_rows === 1) {
                    $row = $result->fetch_assoc();
                    if (password_verify($password, $row['password'])) {
                        session_regenerate_id(true);

                        $_SESSION['user_id'] = $row['id'];
                        $_SESSION['account_type'] = $account_type;
                        $_SESSION['username'] = $row['username'];
                        $_SESSION['first_name'] = $row['first_name'];
                        $_SESSION['last_name'] = $row['last_name'];
                        $_SESSION['email'] = $row['email'];
                        $_SESSION['phone_number'] = $row['phone_number'];

                        if ($account_type === 'teacher') {
                            $_SESSION['title'] = $row['title'];
                        } else {
                            $_SESSION['guardian_phone'] = $row['guardian_phone'];
                            $_SESSION['gender'] = $row['gender'];
                            $_SESSION['level'] = $row['level'];
                        }
                        
                        $token = bin2hex(random_bytes(32));
                        setcookie('user_token', $token, time() + 86400 * 30, "/", "", true, true);
                        $_SESSION['user_token'] = $token;

                        if ($account_type === 'teacher') {
                            sleep(1);
                            header("Location: teacher-dashboard.php");
                        } else {
                            sleep(1);
                            header("Location: student-dashboard.php");
                        }
                        exit();                        
                    } else {
                        $errors[] = 'Username or Password May be Incorrect';
                    }
                } else {
                    $errors[] = 'This Account Is Not Exist';
                }
                $stmt->close();
            }
        }
    }
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
} else {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
?>

session_handler.php:

<?php
require_once 'db_connect.php';

$conn = getDatabaseConnection();

session_set_save_handler(
    'openSession',
    'closeSession',
    'readSession',
    'writeSession',
    'destroySession',
    'gcSession'
);

function openSession() {
    return true;
}

function closeSession() {
    return true;
}

function readSession($id) {
    global $conn;
    $stmt = $conn->prepare("SELECT data FROM sessions WHERE id = ? AND last_accessed > DATE_SUB(NOW(), INTERVAL 30 DAY)");
    $stmt->bind_param("s", $id);
    $stmt->execute();
    $result = $stmt->get_result();

    if ($row = $result->fetch_assoc()) {
        return $row['data'];
    }

    return '';
}

function writeSession($id, $data) {
    global $conn;
    $stmt = $conn->prepare("REPLACE INTO sessions (id, data, last_accessed) VALUES (?, ?, NOW())");
    $stmt->bind_param("ss", $id, $data);
    return $stmt->execute();
}

function destroySession($id) {
    global $conn;
    $stmt = $conn->prepare("DELETE FROM sessions WHERE id = ?");
    $stmt->bind_param("s", $id);
    return $stmt->execute();
}

function gcSession($maxlifetime) {
    global $conn;
    $stmt = $conn->prepare("DELETE FROM sessions WHERE last_accessed < DATE_SUB(NOW(), INTERVAL ? SECOND)");
    $stmt->bind_param("i", $maxlifetime);
    return $stmt->execute();
}

session_start();
?>

tauth.php:

<?php
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

require_once 'session_handler.php';
require_once 'db_connect.php';

try {
    $conn = getDatabaseConnection();

    if (!isset($_SESSION['user_id']) || $_SESSION['account_type'] !== 'teacher') {
        header("Location: login.php");
        exit();
    }

    $user_id = $_SESSION['user_id'];

    $sql = "SELECT * FROM teacher WHERE id = ?";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("i", $user_id);
    $stmt->execute();
    $result = $stmt->get_result();

    if ($result->num_rows > 0) {
        $user = $result->fetch_assoc();

        $_SESSION['first_name'] = htmlspecialchars($user['first_name'], ENT_QUOTES, 'UTF-8');
        $_SESSION['last_name'] = htmlspecialchars($user['last_name'], ENT_QUOTES, 'UTF-8');
        $_SESSION['username'] = htmlspecialchars($user['username'], ENT_QUOTES, 'UTF-8');
        $_SESSION['email'] = htmlspecialchars($user['email'], ENT_QUOTES, 'UTF-8');
        $_SESSION['phone_number'] = htmlspecialchars($user['phone_number'], ENT_QUOTES, 'UTF-8');
        $_SESSION['title'] = htmlspecialchars($user['title'], ENT_QUOTES, 'UTF-8');

        session_regenerate_id(true);

    } else {
        header("Location: login.php");
        exit();
    }
    
    $stmt->close();
} catch (Exception $e) {
    error_log("Error fetching teacher data: {$e->getMessage()}");
    header("Location: error_page.php");
    exit();
}

I have tried to close connection using $conn->close(); but the page goes in failures.

How to run logic the first time a route is accessed in Express.js?

I’m using Express.js, and I want to initialize a cache on every initial request to a route, and on the subsequent ones use the cached value.

For now, I do something like this:

let hasRun = false;

app.get('/my-route', async (req, res) => {
  if (!hasRun) {
    await redisClient.set('key', {});
    hasRun = true;
  }

  const data = await redisClient.get('key');
  res.send(data );
});

But if I have multiple routes, it becomes kind of messy.
What do you suggest?

Note: Even though Redis allows checking if a value exists, I want to ensure the cache is always refreshed and initialized on the first access.

Having trouble hosting a React App on Github Pages

I was wondering if I could get some help on hosting a project I’ve been doing. The repository is here: https://github.com/lazipops/Pokepedia

My problem is hosting it on Github Pages. My project works locally with no problem but when I host it on Github Pages, all I see is a blank screen and in the console it says “main.tsx:1 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “application/octet-stream”. Strict MIME type checking is enforced for module scripts per HTML spec.”

Here’s what I see when I host my repo on Github pages enter image description here

enter image description here

My project is also a React app if that helps. What am I doing wrong?

I’m expecting to host it on Github pages

Pulling values from AsyncStorage to update state in new component

I am new to JS / RN and facing this issue with my first app.

I set data in an onboarding screen and then on the next screen I have about 10 keys I want to check if there is a value in AsyncStorage and if so, update state. I tried to do this with a useEffect and AsyncStorage.getItem, using setData of a variable (created using const [data, setData] = useState({item:key}) – I think it’s called a nested object). This caused an infinite loop / no variables being set depending on my implementation, so I have resorted to creating individual useState objects, plus functions to pull the data from AsyncStorage and then calling these inside a useEffect to run on render (i.e. with an emtpy array as the second variable). This feels very inefficient – what am I doing wrong and how can I improve this?

export default function Profile({ navigation }) {
  const { signOut } = React.useContext(AuthContext);
  const [userName, updateUserName] = React.useState(null);
  // 9 more of these
  async function getUserName() {
    try {
      const savedData = await AsyncStorage.getItem('userName');
      if (savedData != null) {updateUserName(savedData)}
    } catch (error) {
      console.log(error);
    }
  };
  // 9 more of these

  React.useEffect(() => {
    getUserName();
    // 9 more of these
  }, []);

Many thanks for any responses / advice / resources.

Issue with Slider Filtering on Landing Page

I’m building a landing page using Gulp and trying to implement a slider with filtering. I found an example on CodePen (https://codepen.io/chiz-developer/pen/ybxBKy) that demonstrates how to do this. However, when I apply a similar approach to my landing page, I encounter a problem: when I click the filter buttons, my slider disappears. Everything reappears when I click the “All” button.

<section class="section product">
    <div class="container">
      <div class="product__filter product__filter-buttons">
        <button class="product__filter-btn product__all"   data-filter="all" type="button">All</button>
        <button class="product__filter-btn product__chair" data-filter="product__chair" type="button">Chair</button>
        <button class="product__filter-btn product__beds"  data-filter="product__beds" type="button">Beds</button>
        <button class="product__filter-btn product__sofa"  data-filter="product__sofa" type="button">Sofa</button>
        <button class="product__filter-btn product__lamp"  data-filter="product__lamp" type="button">Lamp</button>        
      </div>

      <ul class="product__slider">
        <li class="product__slide product__sofa">
          <article class="productCart">
            <img class="productCart__img" src="images/product/nyantuy.png" alt="">
            <div class="productCart__content">
              <p class="productCart__subtitle">Chair</p>
              <h3 class="productCart__title">Anjay Chair</h3>
              </div>
          </article>
        </li>

        <li class="product__slide product__chair">
          <article class="productCart">
            <img class="productCart__img" src="images/product/anjay.png" alt="">
            <div class="productCart__content">
              <p class="productCart__subtitle">Chair</p>
              <h3 class="productCart__title">Anjay Chair</h3>
              </div>
          </article>
        </li>

        <li class="product__slide product__beds">
          <article class="productCart">
            <img class="productCart__img" src="images/product/baltsar.png" alt="">
            <div class="productCart__content">
              <p class="productCart__subtitle">Chair</p>
              <h3 class="productCart__title">Anjay Chair</h3>
              </div>
          </article>
        </li>

        <li class="product__slide product__lamp">
          <article class="productCart">
            <img class="productCart__img" src="images/product/sakarias.png" alt="">
            <div class="productCart__content">
              <p class="productCart__subtitle">Chair</p>
              <h3 class="productCart__title">Anjay Chair</h3>
              </div>
          </article>
        </li>
      </ul>

    </div>
  </section>

$(function() {
  $(".product__slider").slick({
    slidesToShow: 4,
    slidesToScroll: 4,
    arrows: true,
  });
  
  $(".product__filter-btn").on('click', function() {
    var filter = $(this).data('filter');

    // Перевірте наявність слайдерів перед фільтрацією
    if ($(".product__slider").slick('getSlick').$slides.length === 0) {
      console.log('Слайдери не знайдені');
      return;
    }

    $(".product__slider").slick('slickUnfilter');

    if (filter === 'product__chair') {
      $(".product__slider").slick('slickFilter', '.product__chair');
    } else if (filter === 'product__beds') {
      $(".product__slider").slick('slickFilter', '.product__beds');
    } else if (filter === 'product__sofa') {
      $(".product__slider").slick('slickFilter', '.product__sofa');
    } else if (filter === 'product__lamp') {
      $(".product__slider").slick('slickFilter', '.product__lamp');
    } else if (filter === 'all') {
      $(".product__slider").slick('slickUnfilter');
    }
    
    // Перевірка фільтрації
    console.log('Активний фільтр:', filter);
  });
});

I’m a beginner in JavaScript and web development, so I might have made a mistake. Could you help me figure out what might be going wrong and suggest alternative solutions for implementing slider filtering?

I would greatly appreciate any assistance!

Thank you!

Synchronize authentication on server and client components in Next.js 14

I’m working on a project using Next.js with Express and Prisma, and I’ve hit a snag with authentication. I’m using JWTs stored in an HTTP-only cookie, and while the login and registration are working fine (using fetch in client components with useForm), I’m having trouble with maintaining the authentication synchronized between the server components and client components (when the cookie expires).

Here’s what I’ve set up so far:

I set the authentication context after login/register. I also have a useEffect hook in the AuthProvider that verifies the cookie via a request, ensuring the context remains consistent if the page refreshes but the cookie is still valid.

The issue arises when I perform a fetch in a server component. In that case, the server can easily delete the cookie, but there’s no way to clear the context since it’s not accessible from the server.

I tried to solve this by creating a custom fetch class (customFetch) that allows me to register response interceptors. The idea was to use another useEffect hook in the AuthProvider to register an interceptor that checks for a 401 status code and clears the context. This works in the browser console (I can see the interceptor logs), but it doesn’t seem to log anything in the front-end terminal.

I’m not too keen on implementing global state management at this point, so I feel a bit stuck.

I haven’t posted any code here to avoid clutter, but you can check out the repo on GitHub: Next-js-tech-store. Although the application wouldn’t run locally without docker and all ENV’s, I think you’ll get the idea

Here are the key files related to authentication:

I’d really appreciate it if anyone could point me in the right direction or spot any mistakes I might have missed. Thanks in advance!

Why does the congratulations message not display in a div using document.getElementById

I’ve written the below code and need to change the window.alert messages so that they show in a div box instead. However, I’ve started with the initial congratulations message and it doesn’t appear at all. Below is my code:

<!DOCTYPE html>
<html lang="en">
<head>
<title> Hide And Seek </title>
<meta charset="utf-8">
<script>
var diamond;
var number_of_guesses;

diamond = Math.ceil(Math.random() * 10);

number_of_guesses = 0;

function check(guess) {
    if(diamond == guess)
    {
        // window.alert("Congratulations! You have found the diamond.");
        document.getElementById('messageBox').textContent = 'Congratulations! You have found the diamond!';
        
        again = window.prompt("Would you like to play another game? Enter Y or N.", "Y");
        
        if(again == "N" || again == "n")
        {
            window.alert("Thanks for playing. Goodbye.");
            window.close();
        }
        else
        {
            window.alert("The diamond has been hidden. You can now try again.");
            window.location.reload();
        }
    }
    else
    {
        number_of_guesses = number_of_guesses + 1;
        
        if(diamond < guess)
        {
            result = "lower"
        }
        else
        {
            result = "higher"
        }
        window.alert("Guess number " + number_of_guesses + " is incorrect. Diamond is " + result + ".");
    }
    if(number_of_guesses >= 3)
    {
        window.alert("Sorry, you have run out of guesses! The diamond was in box " + diamond);
        
        again = window.prompt("Would you like to play another game? Enter Y or N.", "Y");
        
        if(again == "N" || again == "n")
        {
            window.alert("Thanks for playing. Goodbye.");
            window.close();
        }
        else
        {
            window.alert("The diamond has been hidden. You can now try again.");
            window.location.reload();
        }
    }
}
</script>
</head>
<body>

<form name="hidenseek">
    <input id="box1" type="button" value="1" onClick="check(box1.value)">
    <input id="box2" type="button" value="2" onClick="check(box2.value)">
    <input id="box3" type="button" value="3" onClick="check(box3.value)">
    <input id="box4" type="button" value="4" onClick="check(box4.value)">
    <input id="box5" type="button" value="5" onClick="check(box5.value)"> <br>
    <input id="box6" type="button" value="6" onClick="check(box6.value)">
    <input id="box7" type="button" value="7" onClick="check(box7.value)">
    <input id="box8" type="button" value="8" onClick="check(box8.value)">
    <input id="box9" type="button" value="9" onClick="check(box9.value)">
    <input id="box10" type="button" value="10" onClick="check(box10.value)"> <p>
</form>

<h3 id="messageBox"> Click on the box of your choice. </h3>

</body>
</html>

I’ve changed all other window.alert messages to the same and they work fine, apart from the congratulations message

What’s wrong in my launch.json- getting a

I am trying to make a website using html5 template. It was working till last week but now it gives me this error- Could not read source map for chrome-error://chromewebdata/: Unexpected 503 response from chrome-error://chromewebdata/neterror.rollup.js.map: Unsupported protocol “chrome-error:”

this is my launch.json

{
“version”: “0.2.0”,
“configurations”: [

    {
        "type": "chrome",
        "request": "launch",
        "name": "Launch Chrome against localhost",
        "url": "http://localhost:8080",
        "preLaunchTask": "npm: start",
        "webRoot": "${workspaceFolder}"
    }
]

}

I tried writing the “prelaunch”: npm: start but it still didnt work

Overlapping carousel images issue

I have a working carousel: images enter from the right side of the screen when clicking on one of the buttons at the bottom, they stay on the screen and move to the left when clicking on another button.

The user can click on any button without a defined order and the images always enter from the right.

The problem is when clicking on a previous adjacent button (try A and B at the code example) , since the image “has not had time to return to its original position”, it enters from the left.

Is there a solution?

const imageContainer = document.getElementById("image-container");
const imageSlides = imageContainer.querySelectorAll(".image-slide");
let currentSlideIndex = 0;

function showImage(slideIndex) {  
  imageSlides.forEach(slide => {  
   slide.classList.remove("active");  
   slide.classList.remove("exit");  
  });  
  
  imageSlides[slideIndex - 1].classList.add("active");  
  
  if (currentSlideIndex > 0) {  
   imageSlides[currentSlideIndex - 1].classList.add("exit");  
  }  
  
  currentSlideIndex = slideIndex;  
}

const buttons = document.querySelectorAll(".gota");

buttons.forEach((button, index) => {
  button.addEventListener("click", () => showImage(index + 1));

});
* {font-family: helvetica; text-align: center; font-size: 14px; font-weight:bold;}

.container {width: 100vw;
height: 100vh; }

.buttons {display:grid; 
width: 100%;
height: 100%; 
grid-template-columns: repeat(auto-fit, minmax(100px, max-content));
gap: 30px;
grid-auto-flow: row;
justify-items: center;
align-items: center;
justify-content: center; 
}

.gota {top:-80px;
width: 25px;
height: 20px;
border-radius: 25%;
background-color:red;
position: relative;
margin: 10px auto;
cursor:pointer;
padding-top:4px;
color:#fff;

}


#image-container {
position: relative;
width: 100%;
height: 200px;
overflow: hidden; top:20%;
}



.image-slide {content:'';
position: absolute;
top: 0;
left: 100%;
width: 100%;
height: 100%;
object-fit: cover;
transition: left 1s ease-in-out;
z-index:0;
}

#image1 {background-color:blue;}
#image2 {background-color:gray;}
#image3 {background-color:brown;}
#image4 {background-color:orange;}
#image5 {background-color:purple;}
#image6 {background-color:darkgreen;}



.image-slide.active {
  left: 0; 
  z-index:20;
}

.image-slide.exit {
  left: -100%;
z-index:20;
}
<div class="container">

<div id="image-container" >
<img src="#" class="image-slide" id="image1">
<img src="#" class="image-slide" id="image2">
<img src="#" class="image-slide" id="image3">
<img src="#" class="image-slide" id="image4">
<img src="#" class="image-slide" id="image5">
<img src="#" class="image-slide" id="image6">
</div>

  
<div class="buttons">  
<div class="gota"></div>
<div class="gota"></div>
<div class="gota">A</div>
<div class="gota">B</div>
<div class="gota"></div>
<div class="gota"></div>
</div>
<div>

Adding Unique Values to a Sharepoint List from an Onclick function on a Website

I maintain my company’s website and we want to see how many times hyperlinks get clicked within a side panel on the website. Each hyperlink has a name on the side panel and I’m trying to have that “name” added to a Sharepoint list on(click). With that being said, I added a class to the anchor tags named “nameLink” then called a function to add “nameLink” to the title column of Sharepoint so I can keep track….

This worked however I have multiple hyperlinks in this side panel and the “name” in Sharepoint is coming across as ALL the names of each hyperlink in that category instead of the one that was clicked. Is there a way to allow each hyperlink to be unique so the Sharepoint data is shown properly? Here is a mock template of my code as I can’t provide the real data.

MY CODE

$("#dataCode").on('click', function() {
            var varUserEmail = $('#useremail').val();
            var varTitle = $('.nameLink').text();
                $().SPServices({
                    operation: "UpdateListItems",
                    async: false,
                    batchCmd: "New",
                    listName: "Analytics",
                    valuepairs: [
                        ["Title", varTitle],
                        ],
                        completefunc: function(xData, Status) {
                    alert('This Worked!');
                }
                });
            });


<ul id="dataCode">
                                                          <li>
                                <a href="link">
                                         <div class="nameLink">Title1</div>
                                </a>
                            </li>
<li>
                                <a href="Link">
                                    <div class="nameLink">Title2</div>
                                </a>
                            </li>`your text`

Iterate over DOM after Thenable Promise

Question one; I want to iterate over the DOM after a Promise, where I fetch a HTML fragment and insert it into the DOM asynchronously. When I use this.parse(), The iteration loop doesn’t seem to log the inserted HTML fragments individually, but it does show the other DOM elements such as its parents, but not its children. I need to access each DOM element individually.

Question two; Even stranger, when I do this.parse instead of this.parse() it does log all the elements, including all fragments as separate DOM elements, which I want. But if I do this.parse, I cannot use “this” to access other functions inside the class otherwise I get a TypeError.

How is this possible, and what would be the solution?

Test.js

class test {
  anotherFunc(value) {
    console.log(value);
  }

  parse() {
    // iterate over all DOM elements.
    const docElements = document.all;
    for (let i = 0; i < docElements.length; i++) {
      console.log(docElements[i]);
      // I need this: this.anotherFunc(docElements[i]);
    }
  }

  page() {
    const promise = fetch('test.txt')
      .then((file) => file.text())
      .then((response) => document.getElementById('test').setHTMLUnsafe(response))
      .then(this.parse());
  }
}

const app = new test();
app.page();

Test.txt

<h1>Test</h1>
<h2>Test</h2>

Index.html

<div id="test"></div>

<script src="test.js"></script>

Expected outcome would be where I am able to iterate over each element in the DOM and be able to call other class functions.

window.open() in Chrome returns null even though the window opens

In Chrome version Version 127.0.6533.101 I’m doing

const {document: a} = window.open("", "GeometryDocumentation", "width=480,height=640");

but get the error Cannot destructure property 'document' of 'window.open(...)' as it is null.

But the window opens with the correct height and width. I’m not blocking popups in chrome nor do I have an ad-blocker. I don’t get this error in Safari.

I’m making this call from inside an iframe so maybe there’s some CORS issue? But the iframe domain matches its parent.

What are the benefits and drawbacks of using inline JS? [closed]

A large number of sites are using inline javascript and a lot of discussion about that. Almost everyone has an opinion and some say we should avoid using inline javascript while others say we can use. Therefore I’m so confused. I have concerns and I have a few questions to ask. What are pros and cons using inline javascript? If we avoid to use, Google warns us “Avoid chaining critical requests”. If we use, problem solved. I really don’t understand, what should we do? Here’s an example of usage. What is the most common realistic view? Sometimes we calculate many things and none fits when actualised.

At least I tried something and I decided to use inline js, do you think I did the right thing?