AEM 6.3 - Sling Model not working - aem

I am using a very basic Sling Model class which is not working at all. This is the class:
package com.aem.sites.models.test;
import org.apache.sling.models.annotations.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import org.apache.sling.api.resource.Resource;
#Model(adaptables=Resource.class)
public class TestModel {
final static Logger logger = LoggerFactory.getLogger(TestModel.class);
private String email;
#PostConstruct
public void init() {
logger.info("=====================================================================inside init method");
email = "something#something.com";
}
public String getEmail() {
return email;
}
}
I have also included the package in the section like this:
I also looked for the Sling Model class here http://localhost:4502/system/console/status-adapters
and found it's entry like this:
Adaptable: org.apache.sling.api.resource.Resource
Providing Bundle: org.apache.sling.models.impl
Available Adapters:
* com.aem.sites.models.test.TestModel
What's more surprising to me is the Sling Model class in the package com.aem.sites.models.header is being called properly.
I don't know what's wrong.
Thanks in advance
Sharing the HTL class:
<sly data-sly-use.bannerObj=com.aem.sites.models.test.TestModel">
<section id="banner"
style="background-image: url('/content/dam/aem-site/banner.jpg')">
<div class="inner">
<h2>Today's temperature is</h2>
<p>
${bannerObj.email}
</p>
<ul class="actions">
<li>Sign Up</li>
<li>Learn More</li>
</ul>
</div>
</section>
</sly>
By not working I mean nothing is happening. No errors or any logs are appearing in the error.log file.

The only issue I see is a syntax error, the data-sly-use attribute's value is not enclosed in quotes properly.
<sly data-sly-use.bannerObj="com.aem.sites.models.test.TestModel">
<section id="banner"
style="background-image: url('/content/dam/aem-site/banner.jpg')">
<div class="inner">
<h2>Today's temperature is</h2>
<p>
${bannerObj.email}
</p>
<ul class="actions">
<li>Sign Up</li>
<li>Learn More</li>
</ul>
</div>
</section>
</sly>
Due to which the HTL file might not have compiled and would have output the entire HTL as is without compiling.

You can check from http://localhost:4502/system/console/status-slingmodels which Sling models are available in your instance and to what resources they are bound.
I would make sure my models are listed and then check for other kind of errors, like typos as mentioned in the comment above.

Related

Dynamic queries and JpaSpecificationExecutor in Spring

I am trying to create a simple Spring project where restaurants can add menu items to shared database and users can use a html form to search the dishes based on a range of criteria- especially dietary requirements
Form example:
Restaurant Name: Chez Hans
Gluten Free: (X)
Egg Free: (X)
Vegan: ()
Example SQL command
Select all FROM "dishes" Dish WHERE restaurant_name = "Chez Hans" AND egg_free = TRUE AND
gluten_Free = TRUE;
A list of dishes that fit their criteria would then be returned to the user.
Any field in the form can be left blank, and not checking a box for example, "vegan" does not mean that criteria should be set as 'false', but rather not included within the query.
Because of this it seemed the best way to handle the issue was using JpaSpecificationExecutor to create dynamic SQL queries (similar to the implementation in the answer to the problem below)
Filtering database rows with spring-data-jpa and spring-mvc
I have created a solution based on my research and prior knowledge. However, when I implement my solution, no dishes are returned- even though there are dishes in the database that fit the search criteria. No errors are being produced, but simply a blank table, so I am not sure where I am going wrong.
I have researched countless articles/videos regarding JpaSpecificationExecutor/dynamic queries but there are parts of the that theory I am still unsure about. This is what I gather about JpaSpecificationExecutor/dynamic queries (but I may be wrong)
The meta model is not need to create dynamic queries but to verify the correctness of database query statements
To create queries using meta-model classes a wrapper class is required (In my example- DishSearch)
The following lines are to cast metamodel SingularAttribute class back to the original class value.
Path dname = root.get(Dish_.dname);
Path vegan= root.get(Dish_.vegan);
I am quite new to Spring and still finding it pretty difficult. Any help or advice would be very much appreciated!
Please see below my DishSpecification class:
package com.bron.demoJPA.specification;
public class DishSpecification implements Specification<Dish> {
private final DishSearch criteria;
public DishSpecification(DishSearch ds) {
criteria =ds;
}
#Override
public Predicate toPredicate(Root<Dish> root, CriteriaQuery<?> query,
CriteriaBuilder cb) {
Path<String> dname = root.get(Dish_.dname);
Path<Boolean> vegan= root.get(Dish_.vegan);
Path<Boolean> eggFree= root.get(Dish_.eggFree);
Path<Boolean> glutenFree= root.get(Dish_.glutenFree);
final List<Predicate> predicates = new ArrayList<Predicate>();
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
if(criteria.isVegan()!=false) {
predicates.add(cb.equal(vegan, criteria.isVegan()));
}
if(criteria.isEggFree()!=false) {
predicates.add(cb.equal(eggFree, criteria.isEggFree()));
}
if(criteria.isGlutenFree()!=false) {
predicates.add(cb.equal(glutenFree, criteria.isGlutenFree()));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
Please see my DishSearch Class:
package com.bron.demoJPA.specification;
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
public class DishSearch {
private Long dishId;
private String dname;
private String description;
private double price;
private boolean vegan;
private boolean glutenFree;
private boolean eggFree;
private AppUser app;
}
Please see my SearchController Class:
#Controller
public class SearchController {
#Autowired
DishRepository drep;
#GetMapping("/showSearchForm")
public String showNewDishForm(Model model) {
// Create model attribute to bind form data
DishSearch dishSearch = new DishSearch();
model.addAttribute("dishSearch", dishSearch);
return "search_Dish";
}
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch")DishSearch dishSearch) {
Specification<Dish> spec = new DishSpecification(dishSearch);
drep.findAll(spec);
return "show_dish_List";
}
}
Please see my DishRepository Class:
#Repository
public interface DishRepository extends JpaRepository<Dish, Long>, JpaSpecificationExecutor<Dish>{
#Transactional
#Modifying
List<Dish> findAll(Specification<Dish> spec);
}
Please see my search_Dish.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Dish Management System</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<div class="container">
<h2> Manage Dishes </h2>
<hr>
</div>
<form action="#" th:action="#{/showDishList}" th:object="${dishSearch}" method="POST">
<div class="col-sm-10 offset-sm-1 text-center">
<input type="text" th:field="*{dname}"
placeholder="Dish Name" class="form-control mb-4 col-10">
</div>
<div class="form-check form-check-inline">
<label class=" form-check-label" for="inlineCheckbox1 ">Vegan?</label>
<input type="checkbox" th:field="*{vegan}" />
<label class="form-check-label" for="inlineCheckbox1">Gluten Free?</label>
<input type="checkbox" th:field="*{glutenFree}" />
<label class="form-check-label" for="inlineCheckbox1">Egg Free?</label>
<input type="checkbox" th:field="*{EggFree}" />
</div>
<br>
<br>
<br>
<br>
<button type="submit" class="btn btn-info col-4"> Search Database</button>
</form>
</div>
<hr>
</body>
</html>
Please see my show_dish_List.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Search Results</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<h1>Dish List</h1>
</div>
<table border="1" class="table table-striped table-responsive-md">
<thead>
<tr>
<th>Dish Name</th>
<th>Dish description</th>
<th>Dish Price</th>
<th>Restaurant</th>
</tr>
</thead>
<tbody>
<tr th:each="dishSearch : ${listDishSearch}">
<td th:text="${dishSearch.dname}"></td>
<td th:text="${dishSearch.description}"></td>
<td th:text="${dishSearch.price}"></td>
</tr>
</tbody>
</table>
<div class="col-sm-10 offset-sm-1 text-center">
<a th:href="#{/showNewDishForm}"
class="btn btn-primary btn-sm mb-3"> Search Again</a>
</div>
----------------------------Update------------------------------
In addition to the answer provided below, in the Dish Specification Class I changed
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
to
if(criteria.getDname()!="") {
predicates.add(cb.equal(dname, criteria.getDname()));
}
and the search is working fine now!
I believe the issue is that you are not adding the result in the Model which is being used to render the page show_dish_List.html, therefore nothing is being populated in the UI. Your UI is expecting the data to be in listDishSearch and there is nothing in that variable.
Update your code to:
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch") DishSearch dishSearch, Model model) {
Specification<Dish> spec = new DishSpecification(dishSearch);
model.addAttribute("listDishSearch", drep.findAll(spec));
return "show_dish_List";
}
and everything should be working fine.
Remove the method findAll from your DishRepository repository. It is already being provided by the interface JpaSpecificationExecutor.

Posting Html with images (WYSIWYG) to ASP.net core controller

I'm having trouble posting my wysiwyg content to my controller in asp.net core. I can't seem to get any value from the form editor. The value for the Content property comes to the controller as null. I'm using the summernote form editor to handle my richtext box editor.
Here is my code
public class Editor
{
public int EditorId { get; set; }
public string Content { get; set; }
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Editor editor)
{
if (ModelState.IsValid)
{
_context.Add(editor);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(editor);
}
View:
<h2>Create</h2>
<h4>Editor</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Content" class="control-label"></label>
<textarea asp-for="Content" id="summernote" name="editordata"></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
<script>
$(document).ready(function () {
$('#summernote').summernote();
});
</script>
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote.js"></script>
}
#section Styles{
<!-- include libraries(jQuery, bootstrap) -->
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet">
<!-- include summernote css/js -->
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote.css" rel="stylesheet">
}
So the issue is when I post the form it's gets to the controller but the content comes over as null. I'm not sure how to post the content
Here are my thoughts, I'm thinking i'm missing a some attribute that allows html to come over the wire to my controller, but all the reserach i've found is that asp.net core doesn't require that. Or I need to handle this type of request in the middleware pipeline, but that doesn't make much sense since it's just html strings i'm sending over the wire to the controller.
It looks like the top of your view was not left out, I assume you have Editor as model.
The problem is on your text area you are using both asp-for and then setting the id and name to something that doesn't match your model property.
You should just use asp-for and let it decide the id and name instead of adding those yourself.
What is really getting posted is a string named editordata because you used that name on the textarea. remove that and it will be named Content to match the property of the model
You also don't need the [Bind] attribute shown in the controller action in your screenshot.
I have been sitting with the same issue and was able to resolve it due to Joe's answer!
Could I suggest working on the summernote class for the text area instead of using your id?
I noticed when I use the id that my textarea's display property doesn't get set to none, but it works when i use the class="summernote".
<textarea asp-for="Instructions" class="summernote"></textarea>
<script>
$(document).ready(function () {
$('.summernote').summernote();
});
</script>
Put this script in your page head:
<script src="https://cdn.ckeditor.com/4.13.0/standard/ckeditor.js"></script>
Lets say you have model called ForumModel where you save contents of editor. Property where you your content is saved is called answer:
public string Answer { get; set; }
So in your view you have following tag:
#model ForumModel
Therefore if you want to add editor:
<textarea id="editor1" asp-for="#Model.Answer" class="form-control" required=""></textarea>
<script>
CKEDITOR.replace("editor1");
</script>
And now all that is left is to call your controller on submit button. When your form is submitted you go to constructor that saves your contents.
public IActionResult Reply(ForumModel forumModel)
{
forumModel.SaveReply();
return RedirectToAction("SomeRandomPage");
}

Scala Play: object index is not a member of package views.html

I'm getting
object index is not a member of package views.html
but unlike all the other threads opened on this subject, my issue seems totally unrelated to the IDE. I get this issue from the command line (no IDE) no matter how much I try to clean and rebuild by running
activator clean compile run
or just
sbt clean compile
Here is my conf/routes:
GET / controllers.Application.index
GET /books controllers.Application.listBooks
POST /books controllers.Application.upload
GET /assets/*file controllers.Assets.at(path="/public", file)
This si my views/index.scala.html:
#import play.api.data.Form
#import models.Book
#(form: Form[Book])(implicit messages: Messages)
<!DOCTYPE html>
<html>
<head>
<title>xxx</title>
<link rel="stylesheet" type="text/css" media="screen" href='#routes.Assets.at("stylesheets/main.css")'>
<script type="text/javascript" href='#routes.Assets.at("javascripts/jquery-1.9.0.min.js")'></script>
</head>
<body>
<div class="screenshot">
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span>
</a> <a class="brand" href="#">Workday Dublin CTF</a>
<div class="nav-collapse">
<ul class="nav">
</ul>
</div>
</div>
</div>
</div>
<h1>All Your Books Are Belong To Us</h1>
<div class="container">
<h2>Add Book</h2>
#helper.form(action = routes.Application.upload, 'enctype -> "multipart/form-data") {
#helper.inputText(form("title"))
#helper.inputText(form("author"))
#helper.inputFile(form("myUpload"))
<div class="form-actions">
<button type="submit" class="btn btn-primary">Create Book</button>
</div>
}
</div>
</div>
</body>
</html>
Finally, here is where the error is thrown, in my controllers/Application.scala:
package controllers
import models.Book
import models.Book._
import play.api.mvc._
class Application extends Controller {
def index = Action {
Ok(views.html.index(Book.form))
}
def listBooks = Action {
Ok(books.head.myUpload)
}
def upload() = Action(parse.multipartFormData) { request =>
request.body.file("myUpload").map { myUpload =>
import java.io.File
val filename = myUpload.filename
val contentType = myUpload.contentType
myUpload.ref.moveTo(new File(s"/tmp/$filename"))
addBook(Book("xxxtitle", "xxxauthor", filename))
Ok("File uploaded at /tmp/"+filename)
}.getOrElse {
Redirect(routes.Application.index).flashing(
"error" -> "Missing file")
}
}
}
The error is thrown at Ok(views.html.index(Book.form)) which references models/Book.scala:
package models
import play.api.data.Form
import play.api.data.Forms._
case class Book(title: String, author: String, myUpload: String)
object Book {
var books = List(Book("title test 1", "author test 1", "filename test 1"))
def addBook(book: Book) = books = books ::: List(book)
val form = Form(mapping(
"title" -> text,
"author" -> text,
"myUpload" -> nonEmptyText)(Book.apply)(Book.unapply))
}
As I've researched a lot about this, and no other solution has worked so far, any help would be immensely appreciated. Thank you so much!
Delete all content from folder /project/target and build on terminal:
sbt compile
Apparently, even in this case the issue was related to the IDE. Despite seemingly unrelated, given it occurred from the command line and even after applying all the changes suggested by others.
I created a new project -> Play 2.x in IntelliJ IDEA 2016.2.2. Then I copy/paste all the content from the old faulty project, within in the new project structure. And everything worked straight away, although I had to add
import play.api.Play.current
import play.api.i18n.Messages.Implicits._
to Application.scala in order to pass the implicit messages (as #curious spotted in the comments). I did not mark his comment as the answer because when I tried to add these imports in the faulty project, I was still getting the same error. So nope, the fix would be something to do wth the IDE settings which I still am not too sure about. Surely my workaround is good enough for me, though.

Referencing individual generated components from ngFor

I have an angular2 component which I have included below. I generate a list of chapters which I then display with an *ngFor= tag, but I want to be able to individually target these in my ng2 component (so I can highlight the selected chapter). I would of thought the below code would generate something like this:
<p class="chapter 1" #1>1. My First Chapter</p>
However, I don't get the #1, hence my selector doesn't work and I can't by default set the first chapter in the list to be selected.
import { Component, ViewChild, ElementRef, AfterViewInit } from '#angular/core';
#Component({
selector: 'tutorial',
template: `
<div class="content row">
<div class="chapters col s3">
<h3>Chapters:</h3>
<p *ngFor="let chapter of chapters" class="chapter" #{{chapter.number}}>{{chapter.number}}. {{chapter.title}}</p>
</div>
</div>
`
})
export class bookComponent implements AfterViewInit {
public chapters = _chapters;
#ViewChild('2') el:ElementRef;
ngAfterViewInit() {
this.el.nativeElement.className += " clicked";
}
}
What should I do to be able to individually select my generated <p> tags?
For you use case this might be a more angulary way
<p *ngFor="let chapter of chapters; let i=index" (click)="clickedItem = i" [class.clicked]="i == clickedItem" class="chapter" #{{chapter.number}}>{{chapter.number}}. {{chapter.title}}</p>
export class bookComponent implements AfterViewInit {
public chapters = _chapters;
clickedItem: number;
}
Updating the model and binding the view to make Angular reflect the model to the view is the preferred way instead of imperatively modifying the DOM.
I would let the NgFor loop control adding or removing the clicked class:
<p *ngFor="let chapter of chapters" class="chapter"
[class.clicked]="chapter.number === selectedChapterNumber">
{{chapter.number}}. {{chapter.title}}
</p>
Then just set selectedChapterNumber appropriately in your component logic.
export class bookComponent {
public chapters = _chapters;
private selectedChapterNumber = 1;
}
You can use directive with HostListener to select an element as shown below.
Working Demo : http://plnkr.co/edit/mtmCKg7kPgZoerqT0UIO?p=preview
import {Directive, Attribute,ElementRef,Renderer,Input,HostListener} from '#angular/core';
#Directive({
selector: '[myAttr]'
})
export class myDir {
constructor(private el:ElementRef,private rd: Renderer){
console.log('fired');
console.log(el.nativeElement);
}
#HostListener('click', ['$event.target'])
onClick(btn) {
if(this.el.nativeElement.className=="selected"){
this.el.nativeElement.className ="";
}else{
this.el.nativeElement.className ="selected";
}
}
}
//our root app component
import {Component} from '#angular/core';
#Component({
selector: 'my-app',
directives:[myDir],
template:
`
<style>
.selected{
color:red;
background:yellow;
}
</style>
<div class="content row">
<div class="chapters col s3">
<h3>Chapters:</h3>
<p myAttr *ngFor="let chapter of chapters" class="chapter" #{{chapter.number}}>{{chapter.number}}. {{chapter.title}}</p>
</div>
</div>
`
})
export class App {
chapters=[{number:1,title:"chapter1"},{number:2,title:"chapter2"},{number:3,title:"chapter3"}]
}

Wicket Error path: 'label1' does not exist for page: BarPage

I would like to assert some label label1 in some application. I write the following junit testcase:
wicketTester.assertLabel("label1", "Hello!");
The page, where the label is added looks like this:
FooPage.java
public class FooPage extends WebPage {
public FooPage() {
add(new Label("label1", "Hello!"));
}
}
and the corresponed html page looks like this:
FooPage.html
<body>
..
...
<div wicket:id="label1"></div>
..
<body>
The label label1 - which i would like to assert- is displayed, when someone clicks on the link
<a wicket:id="fooId" href="FooPage">Foo</a>
in the following page:
<html xmlns:wicket="http://wicket.apache.org/">
<body>
<wicket:panel>
<div class="xxx">
<a wicket:id="fooId"
href="FooPage">Foo</a>
</div>
</wicket:panel>
</body>
</html>
When I run the junit Test, I get the following error:
path: 'label1' does not exist for page: BarPage
My Question is: How to get the right path for the label label1?
Have you clicked link 'fooId' in your test (with wicketTester.clickLink) ?
You can find out your component path like this
Modify WicketApplication class
In Wicket 7
getDebugSettings().setComponentPathAttributeName("component_path");
In Wicket 6 or older
getDebugSettings().setOutputComponentPath(true);
Usage example:
#Override
public RuntimeConfigurationType getConfigurationType() {
if (Boolean.valueOf(getProperty("development.mode"))) {
//show component path in html tag
getDebugSettings().setComponentPathAttributeName("component_path");
return RuntimeConfigurationType.DEVELOPMENT;
}
return RuntimeConfigurationType.DEPLOYMENT;
}
From the web browser if you inspect your component, you will find somthing similar to this:
<input type="text" value="" component_path="pageContent_form_username" name="username" id="username3" >
Please don't forget to change all the underscores with (:) colons like this:
pageContent_form_username -> pageContent:form:username