Objects are not valid as a React child (found: object with keys {…, …}). If you meant to render a collection of children, use an array instead

I am trying to render elements from a JSON schema with the code below, but the children of the paragraph are structured as an array containing React Elements when console-logged. Despite this arrangement, the error mentioned in the title continues to occur, why so?

Am I missing something?

Please go through the code below to understand my plight:

Terminal console.log([paragraph children])

import Image from "@components/Image";
import styles from "../pages/proposals/home.module.sass";
import React, { ReactElement } from "react";
import Editor from "@monaco-editor/react";
import { Tweet } from "react-tweet";

interface ParagraphContent {
  type: "paragraph";
  value: (string | LinkContent | BoldContent)[];
}

interface H1 {
  type: "h1";
  value: string;
}

interface H2 {
  type: "h2";
  value: string;
}

interface H3 {
  type: "h3";
  value: string;
}

interface H4 {
  type: "h4";
  value: string;
}

interface ImageContent {
  type: "image";
  value: string;
  alt?: string;
}

interface LinkContent {
  type: "link";
  value: string;
  text: string;
  target?: string;
}

interface QuoteContent {
  type: "quote";
  value: string;
  cite?: string;
}

interface TweetContent {
  type: "tweet";
  value: string;
}

interface CodeContent {
  type: "code";
  value: string;
  lang: string;
}

interface BoldContent {
  type: "bold";
  value: string;
}

interface CaptionContent {
  type: "caption";
  value: string;
}

type ContentType =
  | ParagraphContent
  | ImageContent
  | CaptionContent
  | CodeContent
  | TweetContent
  | QuoteContent
  | H1
  | H2
  | H3
  | H4;

const renderEngine = (
  content: ContentType[],
  mode: "light" | "dark"
): React.ReactNode => {
  return (
    <>
      {content.map((item, index) => {
        if (item.type === "h1") {
          return (
            <h1
              style={{ marginBottom: "20px", marginTop: "0px" }}
              key={index}
              className={styles.h1}
            >
              {item.value}
            </h1>
          );
        }
        if (item.type === "h2") {
          return (
            <h2
              style={{ marginBottom: "15px", marginTop: "10px" }}
              key={index}
              className={styles.h2}
            >
              {item.value}
            </h2>
          );
        }
        if (item.type === "h3") {
          return (
            <h3
              style={{ marginBottom: "10px", marginTop: "5px" }}
              key={index}
              className={styles.h1}
            >
              {item.value}
            </h3>
          );
        }
        if (item.type === "h4") {
          return (
            <h4 key={index} className={styles.h1}>
              {item.value}
            </h4>
          );
        }
        // Error from the if block?
        if (item.type === "paragraph") {
          let children = item.value.map((innerItem) => {
              if (typeof innerItem === "string") {
                return innerItem;
              } else if (innerItem.type === "link") {
                 return React.createElement(
                   "a",
                   {
                     className: "fancy-link",
                     href: innerItem.value,
                     target: innerItem.target || "_blank",
                   },
                   ` ${innerItem.text} `
                 );
              } else if (innerItem.type === "bold") {
                return React.createElement(
                  "strong",
                  {},
                  ` ${innerItem.value} `
                );
              }
              return null;
            });
          return (
            <p
              style={{ marginBottom: "15px", marginTop: "15px" }}
              className={styles.paragraph}
              key={index}
            >{children}</p>
          );
        }
        if (item.type === "caption") {
          return <caption key={index}>{item.value}</caption>;
        }
        if (item.type === "quote") {
          return (
            <blockquote cite={item.cite} key={index}>
              {item.value}
            </blockquote>
          );
        }
        if (item.type === "image") {
          return (
            <div
              key={index}
              style={{
                display: "flex",
                width: "100%",
                justifyContent: "center",
              }}
            >
              <Image
                alt={item.alt}
                src={item.value}
                style={{ maxWidth: "100%", width: "550px" }}
              />
            </div>
          );
        }
        if (item.type === "code") {
          return (
            <div
              key={index}
              style={{
                display: "flex",
                width: "100%",
                maxWidth: "550px",
                margin: "auto",
                justifyContent: "center",
              }}
            >
              <Editor
                height="300px"
                width={"100%"}
                language={item.lang}
                theme={mode == "light" ? "light" : "vs-dark"}
                loading={
                  <span className={styles.loadingEditor}>loading...</span>
                }
                value={item.value}
                options={{
                  minimap: {
                    enabled: false,
                  },
                  fontSize: 15,
                }}
              />
            </div>
          );
        }
        if (item.type === "tweet") {
          return (
            <div
              key={index}
              className={mode == "light" ? "light" : "dark"}
              style={{
                display: "flex",
                width: "100%",
                justifyContent: "center",
              }}
            >
              <Tweet id={item.value} />
            </div>
          );
        }
        return null;
      })}
    </>
  );
};

export default renderEngine;

//Content JSON
    ..."content": [
    {
        "type": "paragraph",
        "value": [
            "Lorem ipsum...."
        ]
    },
    {
        "type": "paragraph",
        "value": [
            {
                "type": "bold",
                "value": "Lorem ipsum ....:"
            }
        ]
    }
]

Transpose table data in js

I’m working with the datatable component from prime react. This component takes an array of objects and creates a column for each key of the object and a row for each object in the array. This means that this object:


const tableData = [
    {
         code: 5000,
         name: 'Plan 1',
         category: 'Category 1',
         quantity: 1,
    },
    {
         code: 1000,
         name: 'Plan 2',
         category: 'Category 2',
         quantity: 2,
    },
    
    {    
         code: 15000,
         name: 'Plan 3',
         category: 'Category 3',
         quantity: 3,
    },
]

<DataTable value={tableData}>
    <Column field="code" header="Code" />
    <Column field="name" header="Name" />
    <Column field="category" header="Category" />
    <Column field="quantity" header="Quantity" />
</DataTable>

Will produce a table like this:
enter image description here

And so far so good. However, I need a way to manipulate the data so the table will be rendered like this:
enter image description here

As you can see, the headers are now in the first column and each column represents the values for a given code

I think that what I’m basically looking for is a way to transpose the data. I just can’t find how to do it.

Hello Next.js […nextAuth].js File Session Function Calling Questions

I’m just asking you to check this part because I’m working on a project related to Next.js and the session part doesn’t seem to be working in the callback function during the login logic implementation

import NextAuth from 'next-auth';
import CredentialsProvider from "next-auth/providers/credentials";
import {connectDB} from "@/util/mongoDbDatabase";
import {MongoDBAdapter} from "@next-auth/mongodb-adapter";
import CustomCredentialsProvider from "@/app/CredentialsProvider";
export const options = {
    providers: [
        CredentialsProvider({
                name: "credentials",
                async authorize(credentials) {
                    const client = await connectDB
                    const db = client.db("yoong")
                    const user = await db.collection("member").findOne({userId : credentials.userId,   password : credentials.password})
                    if(!user){
                        return null
                    }
                    return user;
                },
        }),
    ],
    session: {
        strategy: 'session',
        maxAge: 30 * 24 * 60 * 60 //30일
    },
    callbacks: {
        async session(session, user) {
            const client = await connectDB
            const db = client.db("yoong")
            db.collection("session").insertOne(user)
            return session;
        },
    },
        adapter : await MongoDBAdapter(await connectDB),
        secret : process.env.NEXTAUTH_SECRET,
};

const CustomLoginPage = () => {
    return (
        <div>
            <CustomCredentialsProvider/>
        </div>
    );
};
export default NextAuth(options);
export const CustomLogin = CustomLoginPage;

Basic logic implemented a personal login page to implement a login method as a session method and applied session information to MongoDB

'use client'
import {useState} from "react";
import {signIn} from "next-auth/react";
import {useRouter} from "next/navigation";
export default function CustomCredentialsProvider({session}) {
    let [id, setId] = useState("")
    let [password, setPassword] = useState("")
    let router = useRouter()
    async function handleSignIn(){
        const result = await signIn('credentials', {
            redirect: false, // 로그인 성공 시 자동으로 페이지를 이동하지 않도록 설정
            userId: id,
            password: password,
            callbackUrl: 'http://localhost:3000/main'
        });
        if(result.error !== undefined && result.error !== null && result.error !== ""){
            alert("로그인에 실패했습니다 사유 : " + result.error)
        }else{
            alert("로그인 성공 : " + result)
            console.log(result)
            await router.push("/main")
        }
    }
 
    return (
        <div className="main">
            < img src="/ProjectYoongMain.png" className="main-image"></img>
            <div className="login">
                <h1>Welcome To PJYoong</h1>
                <div className="input-login">
                    <p>ID</p>
                    <input type="text" onChange={(e)=>{setId(e.target.value)}} placeholder="아이디를 입력하세요" style={{right: 20 + "px"}}></input>
                </div>
                <div className="input-login">
                    <p>PW</p>
                    <input type="password" onChange={(e)=>{setPassword(e.target.value)}} placeholder="비밀번호를 입력하세요"></input>
                </div>
                <div className="f-right">
                    <button type="button" onClick={
                        handleSignIn
                    }>로그인</button>
                </div>
            </div>
        </div>
    )
}

The above code is a custom login code. I’m sharing the reference

First of all, when I logged in before the problem, the login worked normally

async function handleSignIn(){
        const result = await signIn('credentials', {
            redirect: false, // 로그인 성공 시 자동으로 페이지를 이동하지 않도록 설정
            userId: id,
            password: password,
            callbackUrl: 'http://localhost:3000/main'
        });
        if(result.error !== undefined && result.error !== null && result.error !== ""){
            alert("로그인에 실패했습니다 사유 : " + result.error)
        }else{
            alert("로그인 성공 : " + result)
            console.log(result)
            await router.push("/main")
        }
    }
 

When I took a log from the code above, I checked the login information normally, and the server also checked the user login information by checking the DB using the login information. But whether the next step, the callback, doesn’t work

  callbacks: {
        async session(session, user) {
            const client = await connectDB
            const db = client.db("yoong")
            db.collection("session").insertOne(user)
            return session;
        },
    },

Even if I log in from the code above, nothing comes out, and on the /main page that is accessed after login, it was confirmed that the session information was null when outputting the session information with the getServerSession() function. (I definitely logged in and received the login information.) The session information was not stored in the DB that stores the session. I would like to ask if there is anything I missed in that part
Additionally, I checked to see if session information was stored on other storage or cookies (not implemented as a feature, but did not check session information when login was complete), but there was no session information in local storage, session storage, and cookies either

Can you addWizardPage on Uninstaller (QtInstallerFramework)?

I am using QtInstallerFramework and I am trying to add custom page when uninstalling the app.

I have custompage.ui file(simple text) and I am adding it in my package.xml:

<UserInterfaces>
        <UserInterface>custompage.ui</UserInterface>
</UserInterfaces>

And this is how I am using it in my componentscript.js:

Component.prototype.componentLoaded = function ()
{
    installer.addWizardPage(component, "CustomPage", QInstaller.ReadyForInstallation)
}

The problem is that the page is displayed only when I install the application. When I uninstall it, CustomPage is not displayed.

Also, with another approach, if I try to add the customized page in my controlscript.js like this:

Controller.prototype.ReadyForInstallationPageCallback = function ()
{
    try {
        installer.addWizardPage(component, "CustomPage", QInstaller.ReadyForInstallation);
    }
    catch (e) {
        QMessageBox.warning("QMessageBox", "", e, QMessageBox.Ok);
    }
}

I am getting this error:

ReferenceError: component is not defined

So, it looks like the component is not loaded at all when the application is uninstalled.
And from Qt documentation we can add custom pages only in components xml file with <UserInterfaces> tag.
Does this mean that we can not use custom gui pages in the uninstaller or I am missing something?

Environment variables not available in getServerSideProps in Next.js 13 standalone build

I’m running into an issue where my pages aren’t getting their props hydrated. I’m migrating from an older version of NextJS and this is where I’m stuck at the moment. Things work in dev or running next start, but once I use the standalone build, my values are undefined.

next.config.js has: output: “standalone”

myapp/pages/health.tsx

export async function getServerSideProps() {
    console.log(process.env.SOME_VALUE) // this is undefined in the server console
    return {
        props: {
            someValue: process.env.SOME_VALUE || '',
        },
    }
}

One path that temporarily worked was using getStaticProps() instead of getServerSideProps, however, this broke at dynamic routes (ex. [id].tsx, where I don’t know all the IDs in advance to define in getStaticPaths, and even with ‘blocking’ set on fallback, would run into the undefined error again).

I’ve read the docs on environment variables in Next.js extensively, and these values should be available in getServerSideProps.

I know I can update these env vars to have NEXT_PUBLIC prefixes, but I’m wondering why this doesn’t work in getServerSideProps.

Error: Cannot read property of undefined (reading ‘sendEmailWithReceipt’)

I’m trying to send an email with Express, but when i do a POST call to

http://localhost:5001/api/emails/enviarEmail

{
  "sender": "[email protected]",
  "recipient": "[email protected]",
  "subject": "Email subject",
  "bodyEmail": "Email content",
  "proof": "adasdsdad",
  "isSpam": false,
  "isDelivered": true
}

Postman gives: 500 Internal Server Error with this body:

{
    "msg": "Cannot read properties of undefined (reading 'sendEmailWithReceipt')",
    "msgCode": "failure",
    "code": 500
}

What is happening and how can I fix it? Sorry if it’s not very clear, I’m part of a project and this is all new to me

Here is the Service and controller:

import EmailEntity from '../entities/email.entity';
import EmailModel from '../models/email.model';
import EmailRepository from '../repositories/email.repository';
import fs from 'fs';
const emailJsonPath = './src/models/emails.json';

class EmailService {
  private emailRepository: EmailRepository;

  constructor(emailRepository: EmailRepository) {
    this.emailRepository = emailRepository;
  }

  public async sendEmailWithReceipt(data: EmailEntity): Promise<EmailModel> {

    const emailEntity = await this.emailRepository.sendEmailWithReceipt(data);
    const emailModel = new EmailModel(emailEntity);

    return emailModel;
  }
import { Router, Request, Response } from 'express';
import EmailService from '../services/email.service';
import EmailEntity from '../entities/email.entity';
import { SuccessResult } from '../utils/result';
import fs from 'fs';
const emailJson = './src/models/emails.json'

class EmailController {
  private prefix: string = '/emails';
  public router: Router;
  private emailService: EmailService;
  private idCount: number = 1;

  constructor(router: Router, emailService: EmailService) {
    this.router = router;
    this.emailService = emailService;
    this.initRoutes();
  }

  private initRoutes() {
    this.router.post(`${this.prefix}/enviarEmail`, (req: Request, res: Response) =>
      this.sendEmailWithReceipt(req, res));

  private async sendEmailWithReceipt(req: Request, res: Response) {
    req.body.id = this.generateId();
  
    const email = await this.emailService.sendEmailWithReceipt(new EmailEntity(req.body));

    return new SuccessResult({
      msg: 'Email successfully sent',
      data: email
    }).handle(res);
  }

I’ve tried a few times to change the code and adjust the routes, I hope more experienced people can help me, as this is the first time I’ve used this language.

Chrome Extension: how to get element of an iframe with extension file in a content script?

My Chrome extension creates an iframe with an HTML file included in the extension on each web page. I would like to access and modify values of elements in the iframe, but the contentDocument attribute of the iframe object is null.

Here are the files:

manifest.json

{
  "manifest_version": 3,
  "name": "iframe example",
  "version": "1.0",
  "description": "iframe",
  "web_accessible_resources": [
    { "resources": [ "foo.html" ],
      "matches": ["<all_urls>" ]
    }
  ],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ]
}

content.js

(function() {
    const frame = document.createElement('iframe');
    frame.id = 'foo';
    frame.src = chrome.runtime.getURL('foo.html');
    frame.style.width = '100px';
    frame.style.height = '100px';
    frame.style.position = 'fixed';
    frame.style.zIndex = '99999';
    frame.style.top = '0';
    frame.style.left = '0';
    document.body.appendChild(frame);
})();


document.addEventListener('keydown', function(event) {
  if (event.ctrlKey && event.shiftKey && event.code === 'KeyY') {
    frame = document.getElementById('foo');
    console.log(frame.contentDocument.getElementById('foo'));
  }
});

foo.html

<!DOCTYPE html>
<html lang="en">
<body>
<div id="foo">WAITING</div>
</body>
</html>

Error message:

Uncaught TypeError: Cannot read properties of null (reading 'getElementById')

Of course the iframe is fully loaded when I press the keys.

The error is likely due to the web page and the HTML files not being from the same origin. How to resolve the issue? In real case, I need access both to the web page and the iframe as I’d like to extract some content of the web page, transform it and set the value of a div object in the iframe.

Implementing Google ReCAPTCHA V3 Into Website (PHP)

I’m trying to implement Google ReCAPTCHA V3 using the PHP example here: https://stackoverflow.com/a/60036326/1096190

Yesterday’s output was 0.9 but form.js still had issues sending the form. Today, It seems like I am getting a score of 0.3 and its giving me an error.. I’m thinking maybe because I have submitted the form a few times maybe? Either way, it wasn’t working correctly yesterday and wanted to know if anyone can spot something that I have done incorrectly so I can implement and then test with another IP address. Heres what I have so far:

Yesterday’s Output:

mail.php – print_r($response)

{ "success": true, "challenge_ts": "2024-03-05T08:42:59Z", "hostname": "fakedomain.com", "score": 0.9, "action": "homepage" }

form.js

Something went wrong, your message could not be sent.


Today, after more testing I am getting:

mail.php – print_r($response)

{ "success": true, "challenge_ts": "2024-03-06T20:58:07Z", "hostname": "fakedomain.com", "score": 0.3, "action": "homepage" }

form.js

Error! The security token has expired or you are a bot.


What I Have So Far:

HTML File
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Contact</title>
    <link rel="stylesheet" href="/assets/css/style.css" />
    
    
    <!-- Google Recaptcha V3 Begin -->
    <script src="https://www.google.com/recaptcha/api.js?render=reCAPTCHA-site-key-goes-here"></script>
    <!-- Google Recaptcha V3 End -->


</head>
<body>
    <section>
        <div>
            <div class="card">
                <h2 class="card-header">Contact Form</h2>
                <div class="card-body">
                    <form class="contact_form" method="post" action="mail.php">
                        <div class="row">
                            <div class="col-md-6 form-group">
                                <input name="name" type="text" class="form-control" placeholder="Name" required>
                            </div>
                            <div class="col-md-6 form-group">
                                <input name="email" type="email" class="form-control" placeholder="Email" required>
                            </div>
                            <div class="col-md-6 form-group">
                                <input name="phone" type="text" class="form-control" placeholder="Phone" required>
                            </div>
                            <div class="col-md-6 form-group">
                                <input name="subject" type="text" class="form-control" placeholder="Subject" required>
                            </div>
                            <div class="col-12 form-group">
                                <textarea name="message" class="form-control" rows="5" placeholder="Message" required></textarea>
                            </div>
                            <div class="row">
                                <div class="col-12">
                                    <div class="contact_msg" style="display: none">
                                        <p>Your message was sent.</p>
                                    </div>
                                </div>
                            </div>
                            <div class="col-12">
                                <input type="submit" value="Submit Form" class="btn btn-success" name="post">
                            </div>
                            <input type="hidden" id="token" name="token">
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </section>


    <!-- Google Recaptcha V3 Script Begin -->
    <script>
    grecaptcha.ready(function() {
        grecaptcha.execute('reCAPTCHA-site-key-goes-here', {action: 'homepage'}).then(function(token) {
        // console.log(token);
        document.getElementById("token").value = token;
        });
        // refresh token every minute to prevent expiration
        setInterval(function(){
        grecaptcha.execute('reCAPTCHA-site-key-goes-here', {action: 'homepage'}).then(function(token) {
            console.log( 'refreshed token:', token );
            document.getElementById("token").value = token;
        });
        }, 60000);
    });
    </script>
    <!-- Google Recaptcha V3 Script End -->
    

    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>


    <!-- form.js Begin -->
    <script src="form.js"></script>
    <!-- form.js End -->


</body>
</html>
mail.php
<?php

if ($_SERVER["REQUEST_METHOD"] == "POST") {

  # BEGIN Setting reCaptcha v3 validation data
  $url = "https://www.google.com/recaptcha/api/siteverify";
  $data = [
    'secret' => "reCAPTCHA-secret-key-goes-here",
    'response' => $_POST['token'],
    'remoteip' => $_SERVER['REMOTE_ADDR']
  ];

  $options = array(
    'http' => array(
      'header'  => "Content-type: application/x-www-form-urlencodedrn",
      'method'  => 'POST',
      'content' => http_build_query($data)
    )
    );
  
  # Creates and returns stream context with options supplied in options preset 
  $context  = stream_context_create($options);
  # file_get_contents() is the preferred way to read the contents of a file into a string
  $response = file_get_contents($url, false, $context);
  # Takes a JSON encoded string and converts it into a PHP variable
  $res = json_decode($response, true);
  # END setting reCaptcha v3 validation data
   
    print_r($response); 
# Post form OR output alert and bypass post if false. NOTE: score conditional is optional
# since the successful score default is set at >= 0.5 by Google. Some developers want to
# be able to control score result conditions, so I included that in this example.

  if ($res['success'] == true && $res['score'] >= 0.5) {
 
    # Recipient email
    $mail_to = "[email protected]";
    
    # Sender form data
    $subject = trim($_POST["subject"]);
    $name = str_replace(array("r","n"),array(" "," ") , strip_tags(trim($_POST["name"])));
    $email = filter_var(trim($_POST["email"]), FILTER_SANITIZE_EMAIL);
    $phone = trim($_POST["phone"]);
    $message = trim($_POST["message"]);
    
    if (empty($name) OR !filter_var($email, FILTER_VALIDATE_EMAIL) OR empty($phone) OR empty($subject) OR empty($message)) {
      # Set a 400 (bad request) response code and exit
      http_response_code(400);
      echo '<p class="alert-warning">Please complete the form and try again.</p>';
      exit;
    }

    # Mail content
    $content = "Name: $namen";
    $content .= "Email: $emailnn";
    $content .= "Phone: $phonen";
    $content .= "Message:n$messagen";

    # Email headers
    $headers = "From: $name <$email>";

    # Send the email
    $success = mail($mail_to, $subject, $content, $headers);
    
    if ($success) {
      # Set a 200 (okay) response code
      http_response_code(200);
      echo '<p class="alert alert-success">Thank You! Your message has been successfully sent.</p>';
    } else {
      # Set a 500 (internal server error) response code
      http_response_code(500);
      echo '<p class="alert alert-warning">Something went wrong, your message could not be sent.</p>';
    }   

  } else {

    echo '<div class="alert alert-danger">
        Error! The security token has expired or you are a bot.
       </div>';
  }  

} else {
  # Not a POST request, set a 403 (forbidden) response code
  http_response_code(403);
  echo '<p class="alert-warning">There was a problem with your submission, please try again.</p>';
} ?>
form.js
(function ($) {
'use strict';

var form = $('.contact_form'),
  message = $('.contact_msg'),
  form_data;

// Success function
function done_func(response) {
  message.fadeIn()
  message.html(response);
  setTimeout(function () {
    message.fadeOut();
  }, 10000);
  form.find('input:not([type="submit"]), textarea').val('');
}

// fail function
function fail_func(data) {
  message.fadeIn()
  message.html(data.responseText);
  setTimeout(function () {
    message.fadeOut();
  }, 10000);
}

form.submit(function (e) {
  e.preventDefault();
  form_data = $(this).serialize();
  $.ajax({
    type: 'POST',
    url: form.attr('action'),
    data: form_data
  })
  .done(done_func)
  .fail(fail_func);
}); })(jQuery);

Material UI ButtonGroup style props not reflecting

enter image description here

I have a Product image and associated buttons displayed inside a Grid container. The Buttons are conditionally rendered based on some state variables. Basically if the product quantity is 0, it displays a Button (ADD TO CART) else a Button Group (with ‘-‘ , ‘quantity’ , ‘+’ buttons).

I want the Buttons to have a positioning slightly inside the bottom image boundary. This is successfully implemented for the single Add to Cart button using the style props, however the same style props passed to the Button group doesn’t reflect the expected behaviour. And hence the button floats back and forth around the image bottom upon interaction. Any fixes appreciated !

Code below:

<Grid container item xs={2} direction="column" alignItems="center">
      <Grid item sx={{ height: '70%' }}>
        <Box
          component="img"
          src={`/assets/images/products/product_3.jpg`}
          sx={{
            width: '100%',
            height: '100%',
            objectFit: 'cover',
            borderRadius: 1.5,
          }}
        />
      </Grid>
      <Grid item>
        {!productInCart ? (
          <Button
            variant="contained"
            style={{
              top: '-10px',
            }}
            onClick={handleAddToCart}
          >
            ADD TO CART
          </Button>
        ) : (
          <ButtonGroup
            variant="contained"
            style={{
              top: '-10px',
            }}
          >
            <Button onClick={handleRemoveFromCart}>-</Button>
            <Button>{productInCart.quantity}</Button>
            <Button onClick={handleAddToCart}>+</Button>
          </ButtonGroup>
        )}
      </Grid>
    </Grid>

How to Insert a Line Break in a String for Word Document generation Using docx-stamper?

I’m working with docx-stamper in Java to generate Word documents and I’ve hit a snag with inserting line breaks. I’ve tried using n, rn, and other common escape sequences in my strings, but none of these have resulted in actual line breaks in the output document. Is there a specific way to encode line breaks in strings that docx-stamper will recognize and correctly translate into the document? Any advice or code examples would be greatly appreciated.

Thank you!

Knockout Computed field never updates UI

I have some computed fields that I setup as get the model from JSon.

The event is trigered on the related fields change and the calculation is correct but the value is never presented on the UI.

There are some related posts that relates this problem with the previous fill off the model with data. I cannot overcome this, because the model come from the server and I neeed the valies on the model to retur to the server.

MODEL CREATION


self.GetModel = function () {
MyShell().Dialog.showWaitingBox();

    var endpoint = GetUrlBase() + 'api/SDUtils/GetModelFechoCaixa';

    $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        url: endpoint,
        async: false,
        success: function (data) {


            if (self.Entity == null) {
                self.Entity = ko.mapping.fromJS(data);
            } else {
                ko.mapping.fromJS(data, self.Entity);
            }

            MyShell().Dialog.closeWaitingBox();
            ApplyEtiComponents();
        },
        error: function (d) {
            MyShell().Dialog.closeWaitingBox();
            MyShell().Dialog.showMessageBox(0, 0, "error", getMsgTranslated("generic", "ERP Eticadata"),"Erro a obter Modelo", getMsgTranslated("generic", "OK"));
        }
    });
}

COMPUTED FIELDS


self.AutoUpdate = function () {

    self.Entity.Diferencas.MB = ko.computed(function () {
        var Diff = self.Entity.Camping.MB() + self.Entity.eSport.MB() - self.Entity.Caixa.MB();
        console.log("MB:", self.Entity.Caixa.MB(), "DIF", Diff);
        return Diff;
    },self);
    ApplyEtiComponents();
}

Dropzone.js in Blazor Application

I am writing a Blazor application and want to try my hand at JSInterop and the Dropzone.js library. However, I can’t get over the hurdle of transferring the actual attachment data between the javascript and Blazor component for the following scenarios:

  • When a Thumbnail is created
  • When a full image is processed

“Working” Example (Thumbnail)

@using Microsoft.Extensions.Logging

@inject IJSRuntime JSRuntime

@rendermode InteractiveServer

<div class="col-12">
    <div class="card">
        <div class="card-body">
            <h4 class="header-title">Image Uploads</h4>
            
            <div class="row">
                <div class="col">
                    <form action="/" method="post" class="dropzone dz-clickable" id="image-uploads">
                        <div class="dz-message needsclick">
                            <i class="h1 text-muted mdi mdi-upload"></i>
                            <h4>Drop files here or click to upload.</h4>                            
                        </div>
                    </form>
                </div>

                <div class="col">
                    <div class="dropzone-previews mt-3" id="file-previews"></div>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- file preview template -->
<div class="d-none" id="uploadPreviewTemplate">
    <div class="card mt-1 mb-0 shadow-none border">
        <div class="p-2">
            <div class="row align-items-center">
                <div class="col-auto">
                    <img data-dz-thumbnail="" src="#" class="avatar-sm rounded bg-light" alt="">
                </div>
                <div class="col ps-0">
                    <a href="javascript:void(0);" class="text-muted fw-bold" data-dz-name=""></a>
                    <p class="mb-0" data-dz-size=""></p>
                </div>
                <div class="col-auto">
                    <!-- Button -->
                    <a href="" class="btn btn-link btn-lg text-muted" data-dz-remove="">
                        <i class="fe-x"></i>
                    </a>
                </div>
            </div>
        </div>
    </div>
</div>

@code {
    [Parameter, EditorRequired]
    public ImageAttachmentsModel Model { get; set; } = null!;

    [Parameter]
    public EventCallback<ImageAttachmentsModel> ModelChanged { get; set; }

    private DotNetObjectReference<ImageUploads>? objRef;

    [JSInvokable]
    public void OnThumbnailCreated(string name, long sizeBytes, string contentType)
    {
        // Handle the thumbnail creation event
        Console.WriteLine($"Thumbnail created.");
    }

    protected override async Task OnInitializedAsync()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("dropZoneInterop.initializeDropZone", objRef);
        }
    }
}
window.dropZoneInterop = {
    initializeDropZone: function (dotNetHelper) {
        // Initialization logic for Dropzone
        var myDropzone = new Dropzone("#image-uploads",
            {
                paramName: "file",
                maxFilesize: 5,
                acceptedFiles: ".jpg, .jpeg, .png, .gif",
                addRemoveLinks: true,
                previewsContainer: "#file-previews",
                previewTemplate: document.querySelector('#uploadPreviewTemplate').innerHTML,
                init: function () {
                    this.on("thumbnail",
                        function (file, dataUrl) {
                            dotNetHelper.invokeMethodAsync('OnThumbnailCreated', file.name, file.size, file.type);
                        });
                }
            });
    }
};

The Problem

In the javascript, Dropzone has an event that contains dataUrl that the example above doesn’t use:

‘data:image/png;base64,iVBORw0KGgoAAAANSU…’

It is a base64-encoded string. If I try and pass that into the Blazor component as a string it throws an error in the browser. But it’s very generic (Connection Lost).

My Question

Is there a better way to approach passing file data between dropzone and my Blazor component?

How to fix my DataTable so that stateSave will function correctly?

I am trying to use stateSave on a DataTable so when the user selects a project it then goes back to the page puts the DataTable on the page that the project was on. I can’t seem to get the stateSave to work for me. It always seems to reset back to the first page. I tried putting activeTable.draw(false); and inactiveTable.draw(false); with no luck. I see that the data is getting reset each time the table is being built which I believe is overriding the stateSave. I have comment out .clear() but that didn’t help either. I tried checking on populating the table without using .draw() but I found that if I don’t have .draw() then the DataTable doesn’t show the rows.

window.onload = Init;
var activeCnt = 0, inactiveCnt = 0;
var activeTable;


function Init() {
    activeTable = $('#activeTable').DataTable({
        order: [[0, 'asc']],
        columnDefs: [
            { targets: -1, className: 'text-center' }
        ],
        stateSave: true
    });

    inactiveTable = $('#inactiveTable').DataTable({
        order: [[0, 'asc']],
        columnDefs: [
            { targets: -1, className: 'text-center' },
            { targets: -1, className: 'text-center' }
        ],
        stateSave: true
    });

    //Get view
    GetProjectsList();
}

function GetProjectsList() {
    $.ajax({
        url: "/Projects/GetProjects",
        type: 'GET',
        success: function (dta) {
            view = dta;

            PopulateProjectTable();
        }
    });
}

function PopulateProjectTable() {
    activeCnt = 0;
    inactiveCnt = 0;

    // clear project table data
    activeTable.clear();
    inactiveTable.clear();

    for (var i = 0; i < view.projects.length; i++) {
        var prj = view.projects[i];
        var hrTtl = (prj.Sums != null) ? prj.Sums.PrjTotalHours : 0;

        // populate the table
        if (prj.PrjStatusID == 1) { // if project belongs to the active table
            activeTable.row.add([prj.PrjName, prj.PrjProgressName, prj.PrjStartDateStr, prj.PrjEndDateStr, "$" + prj.PrjBudgetAmt + ".00", "$" + prj.PrjBudgetAmt + ".00", hrTtl + " hrs.",
            `<i class="fas fa-search add-pointer text-primary" onclick="ViewProject(${prj.PrjID})"></i><i class="fas fa-edit add-pointer text-primary" onclick="EditProject(${prj.PrjID})" data-bs-toggle="modal" data-bs-target="#modal-prj-details"></i>`]);
            activeCnt++;
        }
        else { // inactive table
            inactiveTable.row.add([prj.PrjName, prj.PrjProgressName, prj.PrjStartDateStr, prj.PrjEndDateStr, "$" + prj.PrjBudgetAmt + ".00", hrTtl + " hrs.", prj.PrjStatusName,
            `<i class="fas fa-search add-pointer text-primary" onclick="ViewProject(${prj.PrjID})"></i><i class="fas fa-edit no-click text-secondary"></i>`]);
            inactiveCnt++;
        }
    }
    
    activeTable.draw(false);
    inactiveTable.draw(false);

    document.getElementById("actCnt").innerHTML = activeCnt;
    document.getElementById("inactCnt").innerHTML = inactiveCnt;


}

What is causing this strange horizontal spacing bug(?) between buttons when appending a List Item element to an Unordered List via JavaScript?

The Problem

There is default spacing between my edit and delete buttons in the HTML. However, when I append a new list item with JavaScript that has the same exact structure and class names, there is no spacing between these buttons.

Desired Behavior
To have the appended buttons appear the same as the “default” buttons in the HTML markup.

Codepen

HTML

            <ul id="list">
                <li class="item">
                    <div>Milk</div>
                    <button class="edit-button">edit</button>
                    <button class="delete-button">X</button>
                </li>
                <li class="item">
                    <div>Cheerios</div>
                    <button class="edit-button">edit</button>
                    <button class="delete-button">X</button>
                </li>
                <li class="item">
                    <div>Cheese</div>
                    <button class="edit-button">edit</button>
                    <button class="delete-button">X</button>
                </li>  
            </ul>

CSS

.title {
    text-align: center;
}

.main {
    border: 1px solid black;
    width: 50%;
    margin: auto;
}

#add-item {
    border: 1px solid black;
}

.input {
    width: 100%;
    padding: 12px 20px;
    margin: 8px 0;
    display: inline-block;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
}

.label {
    margin: 10px;
}

#list {
    flex-direction: column;
    display: flex;
}

#list > li{
    list-style-type: none;
    margin: 10px auto;
}

#list div {
    margin-bottom: 10px;
    text-align: center;
}

/* #list button {
    margin: 0px 4px;
} */

Javascript

// TODO: Grab the list
const shoppingList = document.getElementById("list")
// TODO: Grab the input field
const titleInput = document.getElementById("title")
// TODO: Grab the buttons.
const submitButton = document.getElementById("submit-item")
// const editButtons = document.querySelectorAll(".edit-button")
// const delButtons = document.querySelectorAll(".delete-button")

// TODO: Add click event to the button.
submitButton.addEventListener('click', (e) => {
    e.preventDefault()
    addItem(titleInput.value)
});

// TODO: Create a function to add item.
    // ! Requirement: Must have:
    // !   - item text
    // !   - edit button
    // !   - delete button
    // !   - input field
    // ! Requirement: Add event listeners to buttons

    // TODO: Edit button must get pass the Parent node.

function addItem(title) {
    console.log("Running addItem")
    let newItem = document.createElement("li")
    newItem.classList.add("item")

    let newTitle = document.createElement("div")
    newTitle.textContent = title

    let editBtn = document.createElement("button")
    editBtn.classList.add("edit-button")
    editBtn.innerText = "edit"

    let delBtn = document.createElement("button")
    delBtn.classList.add("delete-button")
    delBtn.innerText = "X"

    editBtn.addEventListener('click', (e) => {
        console.log("Pressed the edit button", e)
        editItem(e.target.parentElement)
    });

    newItem.appendChild(newTitle)
    newItem.appendChild(editBtn)
    newItem.appendChild(delBtn)
    shoppingList.appendChild(newItem)
}


// TODO: Create a function to edit item.
    // ! Requirement: Parent Node (Element) parameter

    // TODO: Remove the Edit, Delete buttons.
    // TODO: Grab text content of the div and assign to variable.
    // TODO: Add an input element to the parent node.
    // TODO: Set input's value to the variable with the text content.
    // TODO: Add the save button.

function editItem(listItem) {
    let title;
    listItem.childNodes.forEach(element => {
        console.log(element.tagName)
        if(element.tagName === "DIV") {
            title = element.innerText
        }
    });

    listItem.innerHTML = ""

    let editInput = document.createElement("input")
    editInput.value = title

    let saveBtn = document.createElement("button")
    saveBtn.classList.add("save-button")
    saveBtn.innerText = "save"

    listItem.append(editInput, saveBtn)

    saveBtn.addEventListener('click', (e) => {
        saveItem(e.target.parentNode)
    });
}

// TODO: Create a function to save item.
    // ! Requirement: Parent Node (Element) parameter
    // TODO: Get the value of the input field and assign to variable
    // TODO: Remove the input and save button.
    // TODO: Create the div, edit, and delete buttons.
    // TODO: Set the div's text content to the variable with the input's value.
    // TODO: Add all those elements to the parent element.

function saveItem(listItem) {
    let titleEdit;

    listItem.childNodes.forEach(element => {
        if(element.tagName === "INPUT") {
            titleEdit = element.value
        }
    });

    listItem.innerHTML = "";

    let changedTitle = document.createElement("div");
    changedTitle.textContent = titleEdit;

    let editBtn = document.createElement("button");
    editBtn.classList.add("edit-button");
    editBtn.innerText = "edit";

    let delBtn = document.createElement("button");
    delBtn.classList.add("delete-button");
    delBtn.innerText = "X";

    listItem.appendChild(changedTitle);
    listItem.appendChild(editBtn);
    listItem.appendChild(delBtn);
}

// TODO: Create a function to delete item.
    // ! Requirement: Parent Node (Element) paramter
    // I believe you can figure this one out yourself. <3 :) 

What I’ve Tried

  • Adding styling to the buttons however, there was still reduced spacing between the buttons in the appended list item. (I expected it to maybe sort out the issue if the buttons had styling applied, it would be the correct spacing for all of them. The HTML elements had 4px of spacing, but it seems like the appended element has 2px spacing.)
  • Checked multiple browsers to see if the browser was rendering differently however, the spacing bug persisted in all browsers. (I was expecting to see a correct version in one of the browsers to pinpoint if it was a rendering issue between browsers.)
  • I tried a CSS reset, the result being default spacing between the HTML buttons and no spacing between the appended buttons. (I was expecting a CSS reset to remove all spacing between buttons, but it seems like it had the default effect as shown in the codepen.)
  • I tried putting my code in a CodePen environment and I still ran into the same issue. (I expected it to work if there was an issue with my local environment.)
  • I checked the code for maybe a carriage space / return and I didn’t find anything. (I expected a hidden space might be the cause and removing it would yield desired results.)
  • I even checked with my instructor and they are not sure either. (They told me to just remove the default list items as a work around, but I am posting because I am genuinely curious why this is happening.)

StackOverflow Articles I’ve Looked At
(I tried linking these but it said these links made my question appear like “Spam” – so, here’s the titles.)

Why are initial CSS styles not visible on DOM element style field?

This is talking about an issue accessing a style’s CSS property, versus accessing the fully rendered CSS properties. This isn’t really applicable since there are not any styles by default in this example.

Appended Element with Missing Styles

Styles are not missing, they’re applied, but the same style is applied differently between the appended elements.

Remove Blank Spaces Between Buttons in HTML CSS

I did a CSS reset, and the issue was still happening. Additionally, this is horizontal and not vertical spacing.

Can I use a DIV inside a List Item?

Checking to see if the HTML structure was valid, and HTML specifications say that I can have divs and other block level elements inside the li.

Appended Content do not get the proper css effect

This person had an issue where the div was appended inside of the UL element, and was causing things to break. This is not my issue.

Appending Elements to DOM with Indentation Spacing

This particular question was having issues with the appended DIV’s HTML structure not being in the correct format. I am not having this issue either. My HTML structure appears to be exactly the same in the Dev Tools.

Strange Error When Appending Elements in JavaScript

This particular issue is encountering a type error. There are no errors in the console. It appears to be a strange formatting / CSS bug.

None of these articles seemed to apply to this particluar issue. I am not sure if this is a bug or not but, considering this is mostly default styling, persistent across browsers, and persists even when styles are added. I’m at a loss.