Categoría: programacion

jhipster – bootstrap dropdown doesn’t work

I wanted to display a dropdown button to provide extra options to the default action. I thought using the bootstrap dropdown options would be a good fit. So, i just grab a sample from the docs and pasted it to the component.

surprisingly to me it wasn’t working, it was showing the main button but nothing happened when I clicked the button to see the options. I went to the dev console and the dropdown menu items were there, so i thought maybe a I had something missing. Check the docs again and thought I should add popper.js as dependency for it to work.

Dropdowns are built on a third party library, Popper.js, which provides dynamic positioning and viewport detection. Be sure to include popper.min.js before Bootstrap’s JavaScript or…

So, I did npm install popper.js but it kept failing to show the options.

Later I found out that jhipster doesn’t use plain old bootstrap but ng-bootstrap instead.

You can see a sample of how to use the dropdown in the entities menu from the navbar.component.html file, where they’ve used ngbDropdown, ngbDropdownToggle and ngbDropdownMenu directives. Or, you can use any sample provided in the ng-bootstrap dropdown documentation, i.e.

now it’s working great! 🔥

Screenshot from 2019-06-20 10-36-41

Anuncios

typescript – computed property on interface

You can’t have computed or calculated properties on interfaces since they omit implementation details, that’s the use of interfaces. For example, we can’t do this 🛑

export interface IUser {
  firstName?: string;
  lastName?: string;
  fullName?: string = this.firstName + this.lastName;
}

but we can just declare it in the interface and implement it in a class

export interface IUser {
  firstName?: string;
  lastName?: string;
  fullName?: string;
}
export class User implements IUser {
  constructor(public firstName?: string, public lastName?: string) {}

  get fullName(): string {
    return `${this.firstName} ${this.lastName}`;
  }
}

now let's see how we can instantiate those class

User user = new User('Jhon', 'Doe');
console.log(user.fullName); // Jhon Doe

the problem I had was the data was coming from a service

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data;
})

changing declared type of reponses won't make a difference 🤷

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: User[])=>{
this.users = data;
})

neither 'cast' (which in typescript its not casting but just an assertion) response objects to class type

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data.map(value => (value as User));
})

i tried to did it by copying properties to a new object of the correct class with spread operator syntax

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data.map(value => {
return {...new User(), ...value} as User;
});
})

it turns out spread syntax produce a plain or literal object so it can't be used to accomplish what we we're trying to do. We need to use the Object.assign method (be aware there could be undesirable or unexpected results).

this.userService.query().pipe(
filter((res: HttpResponse) => res.ok),
map((res: HttpResponse) => res.body)
)
.subscribe((data: IUser[])=>{
this.users = data.map(value => {
return Object.assign(new User(), value);
});
})

great! 😄

UPDATE: 2019-06-24
Although it worked I was assuming it would only be used in just one component, and of course it didn't.
So, it's way easier to just add the computed field in the domain object or DTO on the server, i.e.

UserDTO.java

public String getFullName() {
    return getFirstName() + " " + getLastName();
}

If you can't change the model or just insist on computing at client side, then it's better if you do it at a central location, i.e. the Service

  query(req?: any): Observable {
    return this.http.get('/api/users', { params: options, observe: 'response' })
      .pipe(
        map(res => {
          const users = res.body.map(user => {
            return Object.assign(new User(), user);
          });
          return new HttpResponse({...res, body: users});
        })
      );
  }

sources:
https://stackoverflow.com/questions/53238881/computed-property-in-typescript
https://stackoverflow.com/questions/49937677/how-to-merge-class-instances-in-typescript

java – convert between LocalDateTime and XMLGregorianCalendar

There are plenty of examples converting LocalDate to XMLGregorianCalendar but I couldn’t find any to convert from LocalDateTime except this post where I found the answer.

Instead of using the toString() method of the LocalDateTime we should use the format method with an ISO formatter.

LocalDateTime dt = LocalDate.now().atStartOfDay();

XMLGregorianCalendar xmlDateTime = DatatypeFactory.newInstance().newXMLGregorianCalendar(dt.format(DateTimeFormatter.ISO_DATE_TIME));

The reason is the former omits the seconds and nanoseconds if they’re zeros.

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {

    public static void main(String[] args) {
        LocalDateTime dt = LocalDate.now().atStartOfDay();
        System.out.println("LocalDateTime toString: " + dt.toString());
        System.out.println("LocalDateTime formatISO: " + dt.format(DateTimeFormatter.ISO_DATE_TIME));
    }
}

LocalDateTime toString: 2019-06-17T00:00
LocalDateTime formatISO: 2019-06-17T00:00:00

angular – Spring GetMapping with JSON parameter throwing HTTP 400 – Bad Request

I had a pretty simple REST service implemented with Spring Web and it was throwing a HTTP 400 – Bad Request Error.

This was the implementation

@GetMapping("titulos/preview")
    public void preview(@RequestParam String titulo, HttpServletResponse response) throws DatatypeConfigurationException, JAXBException, IOException {
        log.debug("REST request to preview Titulo: {}", titulo);
        Titulo tituloParsed = mapper.readValue(titulo, Titulo.class);
        String xml = titulosService.toXML(tituloParsed);
        String url = "http://birtviewer/viewer/run?__report=report/rptTitulo.rptdesign&__format=pdf";
        url += "&payload=" + URLEncoder.encode(xml, "utf-8");
        response.sendRedirect(url);
    }

Nothing wrong with it, it just receives JSON as a parameter and converts it to its XML representation in order to forward it to a BIRT report viewer instance. Still, it was throwing the aforementioned error whenever I was calling it from the client with a JSON payload, opening in a new window or tab.

window.open(`${this.resourceUrl}/preview?titulo=${JSON.stringify(titulo)}`, '_blank');

It turned out that I wasn’t URL encoding the JSON value before sending it to the service. This was causing the error due to the parameter not being recognized and being required by default. I just had to do that to get rid of the error.

window.open(`${this.resourceUrl}/preview?titulo=${encodeURIComponent(JSON.stringify(titulo))}`, '_blank');

sources:
https://stackoverflow.com/questions/29823626/angular-http-post-to-target-blank
https://stackoverflow.com/questions/38372134/how-to-convert-an-object-to-json-correctly-in-angular-2-with-typescript
https://stackoverflow.com/questions/40799609/set-headers-while-submitting-a-form-data
https://developer.mozilla.org/es/docs/Web/HTTP/Status/400

birt – add report border pattern

Screenshot from 2019-06-04 15-05-42

I was trying to add a border with a pattern in a report. As it happens, the easiest way to do this is to simply use a background image as recalled here.

First, let’s create our background image with the help of GIMP. Create a new image using the template US-Letter (300 ppp) and adjust the Advanced Settings to set a resolution of 72 ppp.

Screenshot from 2019-06-04 15-11-00

then add the pattern you would like to use. I just pasted an image and scaled it to fit the size of the page. You can use advanced image search from google to specify the size you are looking for 612×792 pixels in this case. You can optimize your image by removing the background and maybe specify a color palette or convert it to black and white and use GIF format, I didn’t need it though. Export the resulting image and copy it to your report project folder.

Screenshot from 2019-06-04 15-12-45

Screenshot from 2019-06-04 15-13-31

Finally, set this image as Background image in the Master Page of your report in the Advanced tab of the Property Editor. You may also want to set the Background size width to cover for a better fit.

Screenshot from 2019-06-04 15-16-04

Depending on the output the results would vary. In our case we only needed it in PDF format which dispplays just fine.

birt – create report from XML data sent as parameter

Not long ago I published an article on how to create a report from JSON sent as parameter. Now is the turn for XML data. The principles are almost the same.

We need to create a new XML data source pointing to a XML file which contains the actual data to be displayed on the report or the XSD definition file.

Screenshot from 2019-06-04 14-32-12

Screenshot from 2019-06-04 14-33-39

then we can define our Data Set using this Data Source

Screenshot from 2019-06-04 14-38-48

Screenshot from 2019-06-04 14-39-09

We need to select which node contains the records we’re going to show and map the fields accordingly.

Screenshot from 2019-06-04 14-39-46

Screenshot from 2019-06-04 14-39-58

Screenshot from 2019-06-04 14-40-44

Screenshot from 2019-06-04 14-40-53

Screenshot from 2019-06-04 14-41-06

Now we can drag and drop our Data Set to create a table in our report.

Screenshot from 2019-06-04 14-42-26

Screenshot from 2019-06-04 14-43-52

PDF
Screenshot from 2019-06-04 14-44-12

Let’s create our parameter named ‘payload’ which will receive the XML sent from the client.

Screenshot from 2019-06-04 14-45-11

now, let’s replace at runtime the XML within the file with the XML we received as parameter. Just add the following code to the script tab of the Data Source we created earlier.

importPackage( Packages.java.io );

xml = new java.lang.String(params['payload']);
bais = new ByteArrayInputStream(xml.getBytes());
ctx = reportContext.getAppContext();

ctx.put('org.eclipse.datatools.enablement.oda.xml.inputStream', bais);

boom! we’re done.

sources:
https://cirovladimir.wordpress.com/2019/05/15/birt-create-report-from-json-data-sent-as-parameter/

Use JSON as a Scripted Data Set


https://www.eclipse.org/forums/index.php/t/162952/