Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialSagar Thakkar
8,814 PointsNo BackGround colour came on flash msg,coded as shown in video
layout.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:fragment="head(page_title)" lang="en">
<meta charset="UTF-8"/>
<meta description="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" th:href="@{/favicon.png}" />
<link rel="stylesheet" th:href="@{/vendor/materialize/css/materialize.css}" />
<link rel="stylesheet" th:href="@{/vendor/codrops/css/cs-select.css}" />
<link rel="stylesheet" th:href="@{/vendor/codrops/css/cs-skin-border.css}" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" th:href="@{/app.css}" />
<title th:text="'giflib | ' + ${page_title}">giflib</title>
</head>
<body>
<div th:fragment="nav" class="navbar-fixed">
<nav>
<div class="container">
<a th:href="@{/}" class="brand-logo">gif<span>.</span>lib</a>
<a href="#" data-activates="mobile-nav" class="button-collapse right"><i class="material-icons">menu</i></a>
<ul class="right hide-on-med-and-down">
<li th:classappend="${#httpServletRequest.servletPath.equals('/upload') ? 'active' : ''}"><a th:href="@{/upload}">Upload</a></li>
<li th:classappend="${#httpServletRequest.servletPath.equals('/') ? 'active' : ''}"><a th:href="@{/}">Explore</a></li>
<li th:classappend="${#httpServletRequest.servletPath.equals('/categories') ? 'active' : ''}"><a th:href="@{/categories}">Categories</a></li>
<li th:classappend="${#httpServletRequest.servletPath.equals('/favorites') ? 'active' : ''}"><a th:href="@{/favorites}">Favorites</a></li>
</ul>
<ul id="mobile-nav" class="side-nav">
<li th:classappend="${#httpServletRequest.servletPath.equals('/upload') ? 'active' : ''}"><a th:href="@{/upload}">Upload</a></li>
<li th:classappend="${#httpServletRequest.servletPath.equals('/') ? 'active' : ''}"><a th:href="@{/}">Explore</a></li>
<li th:classappend="${#httpServletRequest.servletPath.equals('/categories') ? 'active' : ''}"><a th:href="@{/categories}">Categories</a></li>
<li th:classappend="${#httpServletRequest.servletPath.equals('/favorites') ? 'active' : ''}"><a th:href="@{/favorites}">Favorites</a></li>
</ul>
</div>
</nav>
</div>
<div th:fragment="searchbar" class="search-bar container">
<div class="row">
<div class="col s12">
<form th:action="@{/search}" method="get">
<div class="input-field">
<input name="q" type="search" placeholder="Search all gifs..." required="required" autocomplete="off"/>
<i class="material-icons">search</i>
</div>
</form>
</div>
</div>
</div>
<div th:fragment="flash" th:if="${flash != null}" class="container">
<i class="right material-icons" data-close="">close</i>
<div th:classappend="${#strings.toLowerCase(flash.status)}" th:text="${flash.message}" class="flash"></div>
</div>
<div th:fragment="scripts">
<script th:src="@{/vendor/jquery/jquery-1.11.3.js}"></script>
<script th:src="@{/vendor/materialize/js/materialize.js}"></script>
<script th:src="@{/vendor/codrops/js/classie.js}"></script>
<script th:src="@{/vendor/codrops/js/selectFx.js}"></script>
<script th:src="@{/app.js}"></script>
</div>
</body>
</html>
form.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" >
<head th:replace="layout :: head('new category')"></head>
<body>
<div th:replace="layout :: nav"></div>
<div th:replace="layout :: flash"></div>
<div class="container">
<form th:action="@{/categories}" method="post" th:object="${category}">
<div class="row">
<div class="col s12">
<h2>New Category</h2>
</div>
</div>
<div class="divider"></div>
<div class="row">
<div class="col s12 l8" th:classappend="${#fields.hasErrors('name')}? 'error' : ''">
<input type="text" th:field="*{name}" placeholder="Category Name"/>
<div class="error-message" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
</div>
</div>
<div class="row">
<div class="col s12 l8" th:classappend="${#fields.hasErrors('colorCode')}? 'error' : ''">
<select th:field="*{colorCode}" class="cs-select cs-skin-border">
<option value="" disabled="disabled">Category Color</option>
<option th:each = "color : ${color}" th:value = "${color.hexCode}" th:text="${color.name}" th:style="|color:${color.hexCode}|">Aqua</option>
</select>
<div class="error-message" th:if="${#fields.hasErrors('colorCode')}" th:errors="*{colorCode}"></div>
</div>
</div>
<div class="row">
<div class="col s12 l8">
<button type="submit" class="button">Add</button>
<a th:href="@{/categories}" class="button">Cancel</a>
</div>
</div>
</form>
<div class="row delete">
<div class="col s12 l8">
<form>
<button type="submit" class="button">Delete</button>
</form>
</div>
</div>
</div>
<div th:replace="layout :: scripts"></div>
</body>
</html>
CategoryController.java
package com.teamtreehouse.giflib.web.controller;
import com.teamtreehouse.giflib.model.Category;
import com.teamtreehouse.giflib.service.CategoryService;
import com.teamtreehouse.giflib.web.Color;
import com.teamtreehouse.giflib.web.FlashMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.util.List;
@Controller
public class CategoryController {
@Autowired
private CategoryService categoryService;
// Index of all categories
@SuppressWarnings("unchecked")
@RequestMapping("/categories")
public String listCategories(Model model) {
// TODO: Get all categories
List<Category> categories = categoryService.findAll();
model.addAttribute("categories",categories);
return "category/index";
}
// Single category page
@RequestMapping("/categories/{categoryId}")
public String category(@PathVariable Long categoryId, Model model) {
// TODO: Get the category given by categoryId
Category category = null;
model.addAttribute("category", category);
return "category/details";
}
// Form for adding a new category
@RequestMapping("categories/add")
public String formNewCategory(Model model) {
// TODO: Add model attributes needed for new form
if (!model.containsAttribute("category")) {
model.addAttribute("category", new Category());
}
model.addAttribute("color", Color.values());
return "category/form";
}
// Form for editing an existing category
@RequestMapping("categories/{categoryId}/edit")
public String formEditCategory(@PathVariable Long categoryId, Model model) {
// TODO: Add model attributes needed for edit form
return "category/form";
}
// Update an existing category
@RequestMapping(value = "/categories/{categoryId}", method = RequestMethod.POST)
public String updateCategory() {
// TODO: Update category if valid data was received
// TODO: Redirect browser to /categories
return null;
}
// Add a category
@RequestMapping(value = "/categories", method = RequestMethod.POST)
public String addCategory(@Validated Category category, BindingResult result, RedirectAttributes redirectAttributes) {
// TODO: Add category if valid data was received
if(result.hasErrors()){
// Include validation errors upon redirect
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.category", result);
// Add category if invalid was received
redirectAttributes.addFlashAttribute("category", category);
// Redirect back to the form
return "redirect:/categories/add";
}
categoryService.save(category);
redirectAttributes.addFlashAttribute("flash",new FlashMessage("Category successfully added!",FlashMessage.Status.SUCESS));
// TODO: Redirect browser to /categories
return "redirect:/categories";
}
// Delete an existing category
@RequestMapping(value = "/categories/{categoryId}/delete", method = RequestMethod.POST)
public String deleteCategory(@PathVariable Long categoryId) {
// TODO: Delete category if it contains no GIFs
// TODO: Redirect browser to /categories
return null;
}
}
1 Answer
Boban Talevski
24,793 PointsYour problem lies with a typo in the enum value SUCCESS.
You have it here in your controller method as FlashMessage.Status.SUCESS and the app compiles and works without a problem, since you probably have it written that way in your FlashMessage class as well. But the thing is, the thymeleaf fragment in layout.html is using that particular enum value (to lower case) to add a css class to the flash message:
<div th:fragment="flash" th:if="${flash != null}" class="container">
<i class="right material-icons" data-close="">close</i>
<!-- The line below -->
<div th:classappend="${#strings.toLowerCase(flash.status)}" th:text="${flash.message}" class="flash"></div>
</div>
And you guessed it, that particular css class adds the background color to the flash message :) The snippet below is from the app.css file
.flash.success {
background-color: #7f9e40;
color: #f3f6ee;
}
.flash.failure {
background-color: #ac4343;
color: #f2e2e2;
}
But since in your case, the class name will evaluate to sucess instead of success, and there's no sucess css class defined, the appropriate background color won't be applied.