I'm trying to learn Golang. I want to do simply sending data to view. But data is does not reaching to main.gohtml. I could not understand the reason. If I print the data out of the define it works. But If I want to print data in the define "content" (goes to main.gohtml), data is coming empty.
define "title" part is working. Just I cant send data with variable. If I delete {{.text}} part and write something, it works.
main.go file
var tpl *template.Template
func init() {
tpl = template.Must(template.ParseGlob("template/*.gohtml"))
}
func main() {
http.HandleFunc("/about", fabout)
http.ListenAndServe(":80", nil)
}
func fabout(w http.ResponseWriter, r *http.Request) {
values, isset := r.URL.Query()["text"]
var value string
if isset == true {
value = values[0]
} else {
value = ""
}
data := map[string]interface{}{
"text": value,
}
tpl.ExecuteTemplate(w, "about.gohtml", data)
}
about.gohtml
{{template "main"}}
{{define "title"}}About me{{end}} //this is working
{{define "content"}}{{.text}}{{end}} //this is not working
{{.text}} //this is working
main.gohtml
{{define "main"}}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{template "title"}}</title>
</head>
<body>
<ul>
<li>Page 1</li>
<li>Page 2</li>
<li>Page 3</li>
<li>Page 4</li>
<li>Page 5</li>
</ul>
<div style="padding:100px 0;">{{template "content"}}</div>
<footer>
this is footer
</footer>
</body>
</html>
{{end}}
When calling a template you need to pass in any necessary data. The syntax from the docs is:
{{template "name"}} The template with the specified name is executed with nil data.
{{template "name" pipeline}} The template with the specified name is executed with dot set to the value of the pipeline.
So a simple way to fix this is to pass . in when calling main:
{{template "main" .}
and the same when calling content:
{{template "content" .}}
And finally content can use the value:
{{define "content"}}{{.text}}{{end}}
note: Using the argument . passes all data; you could also just pass .text into main (and then use . when calling content and within content ({{.}}).
For a simplified working example see this playground.
My Observation is :
here in this below function , variable value is empty. there I added line (value = "Okay") for testing and is found working.
func fabout(w http.ResponseWriter, r *http.Request) {
values, isset := r.URL.Query()["text"]
var value string
if isset == true {
value = values[0]
} else {
value = ""
}
value = "Okay" // THIS LINE ADDED EXTRA
data := map[string]interface{}{
"text": value,
}
tpl.ExecuteTemplate(w, "about.gohtml", data)
}
Related
I am sending password reset link to my users using cognito CustomMessage_ForgotPassword event. Here is my handler code.
func handler(ctx context.Context, event *events.CognitoEventUserPoolsCustomMessage) (*events.CognitoEventUserPoolsCustomMessage,error)
{
resetURL := fmt.Sprintf("%s/login/recover", os.Getenv("DOMAIN_URL"))
var customMessageForgotPassword = fmt.Sprintf(
`<style>
p {
display: block;
}
</style>
<div tabindex="-1"><p>Hello,</p>
<p> Click on link below to reset your password.</p>
<p> Reset Password </p>
<p>Thanks</p>
</div>`,
resetURL,
event.Request.CodeParameter, event.Request.UserAttributes["Email"])
if event.TriggerSource == "CustomMessage_ForgotPassword" {
event.Response.EmailMessage = customMessageForgotPassword
event.Response.EmailSubject = "Reset Your Password"
}
return event, nil
}
Here is the definition of CognitoEventUserPoolsCustomMessageRequest in cognito.go file.
type CognitoEventUserPoolsCustomMessage struct {
CognitoEventUserPoolsHeader
Request CognitoEventUserPoolsCustomMessageRequest `json:"request"`
Response CognitoEventUserPoolsCustomMessageResponse `json:"response"`
}
type CognitoEventUserPoolsCustomMessageRequest struct {
UserAttributes map[string]interface{} `json:"userAttributes"`
CodeParameter string `json:"codeParameter"`
UsernameParameter string `json:"usernameParameter"`
ClientMetadata map[string]string `json:"clientMetadata"`
}
In email I am getting Reset password url parameters like Domain_URL/login/recover?code=13578&email=%!s()
Tried with parameters like UsernameParameter and some other solutions. But always getting nil here.
Any solution to this problem?
I'm trying to build an app with navigation tabs and trying to use the best way to give state to the entire app. Currently the tabs are functional, but I am struggling to implement a way to both map and restore tab navigation via state in rust using the Yew frontent single page app framework. How do I link these tabs and their respective context sections to state?
Source files on github:
My goal is to:
Implement stateful tab navigation using Rust and the Yew crate.
I've setup a toggle_tab function which uses the STDweb library to iterate over the existing HTML via class of tabcontent, set attribute ("style", "display: none;") . Then I match based on a unique class name (input via function and called from an onclick from exiting HTML) .
From the Yew Examples on Github, I know I may need to implement storage into state and state into Model. What is a good way to implement app navigation with Yew & Rust?
HTML and Toggle Function:
impl Renderable<Model> for Model {
fn view(&self) -> Html<Self> {
html! {
<>
<nav class="tab grey lighten-2">
<div class="nav-wrapper">
// BUTTONS
<ul class="row">
<div class="col s1" >
<button class="tablinks brand-logo welcome " onclick=|e| toggle_tab(e, ".welcome")>{"Welcome"}</button>
</div>
<div class="col s1 push-s1" >
<button class="tablinks brand-logo home active" onclick=|e| toggle_tab(e, ".home")>{"Home"}</button>
</div>
</ul>
</div>
</nav>
//SNIPPETS
<div class="tabcontent white welcome content" >
<Welcome/>
</div>
<div class="tabcontent white home content" style="display: block;">
// <HomeTabs/>
</div>
</>
}
}
}
fn toggle_tab(event: ClickEvent, tab_unique_class_name: &str) {
use crate::stdweb::web::{IElement, IParentNode, INonElementParentNode};
// Get all elements with class="tabcontent" and hide them
for tab in document().query_selector_all(".tabcontent").unwrap() {
let tab: Element = tab.try_into().unwrap();
tab.set_attribute("style", "display: none;").unwrap();
}
// Get all elements with class="tablinks" and remove the class "active"
for tab in document().query_selector_all(".tablinks").unwrap() {
let tab: Element = tab.try_into().unwrap();
tab.class_list().remove("active");
}
let matching_tabs = document().query_selector_all(tab_unique_class_name).unwrap();
match tab_unique_class_name {
".welcome" => {
for elem in matching_tabs.iter() {
let elem: Element = elem.try_into().unwrap();
elem.class_list().add("active");
elem.set_attribute("style", "display: block");
}
}
".home" => {
for elem in matching_tabs.iter() {
let elem: Element = elem.try_into().unwrap();
elem.class_list().add("active");
elem.set_attribute("style", "display: block");
document().get_element_by_id("dashboard").unwrap().set_attribute("style", "display: block;");
}
}
".campaign" => {
for elem in matching_tabs.iter() {
let elem: Element = elem.try_into().unwrap();
elem.class_list().add("active");
elem.set_attribute("style", "display: block");
}
}
".comming_soon" => {
for elem in matching_tabs.iter() {
let elem: Element = elem.try_into().unwrap();
elem.class_list().add("active");
elem.set_attribute("style", "display: block");
}
}
_ => alert("Catchall WHoahw!"),
}
}
Source code
If seeing more code helps, I uploaded the current source code here https://github.com/robust-systems/Rust_MVC/blob/master/src/components/tabs_level_1.rs
This is quite important and any guidance from you is very much appreciated.
app appearance
toggle tab function
Html code
Model, State, Msg, Filter
I realize that this is quite an abstract & verbose question so If any progress is made I will update it here.
Answer from Yew Gitter;
#robust-systems (without looking at the other source code provided, just the code visible in the SO post) My suggestion would be to to emit a Message containing an enum representing which page you want tab you want to be selected instead of running toggle_tab. You can handle this Message in update and store the enum as part of your Model, indicating which is active.
From there, back in view, one way to utilize this state in the Model is to create small html snippets that you stitch together.
eg like:
let welcome_button = if let Tab::Welcome = self.active_tab {
html!{
<button class="tablinks brand-logo welcome active " onclick=self.link.callback(|_| Message::ChangeTab(Tab::Welcome))>{"Welcome"}</button>
}
} else {
html!{
<button class="tablinks brand-logo welcome " onclick=self.link.callback(|_| Message::ChangeTab(Tab::Welcome))>{"Welcome"}</button>
}
};
Then in your large html! block, you insert the `welcome button like
<ul class="row">
<div class="col s1" >
{welcome_button}
...
Thoughts
How to now emit the msg and to where, i will hack up the Custom-Components example on the yew github page. *will edit this answer once the application is fully stateful.
Update
I finally got it fully stateful! Here is the resulting code for anyone who happens to find it useful.
I had to match a ChangeTab(Tab) Message and save the active_tab field in Model to Local Storage, then use an if let to restore the active_tab.
use crate::button_welcome::WelcomeButton;
use crate::button_home::HomeButton;
use crate::button_comming_soon::CommingSoon;
use crate::button_debug_panel::DebugButton;
use serde_derive::{Deserialize, Serialize};
use yew::prelude::*;
use yew::services::storage::{StorageService, Area};
use yew::format::Json;
use crate::tab_navigation::Tab::Home;
use std::sync::atomic::Ordering::AcqRel;
const RESTORE_KEY: &'static str = "tab_navigation";
pub struct TabNavigation {
active_tab: Tab,
storage: StorageService,
}
pub enum Msg {
ChangeTab(Tab),
}
#[derive(Serialize, Deserialize)]
pub enum Tab {
Welcome,
Home,
CommingSoon,
Debug,
}
impl Default for Tab {
fn default() -> Self {
Tab::Home
}
}
impl Component for TabNavigation {
type Message = Msg;
type Properties = ();
fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
let storage = StorageService::new(Area::Local);
let active_tab: Tab = {
if let Json(Ok(active_tab)) = storage.restore(RESTORE_KEY) {
active_tab
} else {
Tab::Home
}
};
TabNavigation {
storage: storage,
active_tab: active_tab,
}
}
fn update(&mut self, msg: Self::Message) -> ShouldRender {
match msg {
// active tab enum
Msg::ChangeTab(tab_to_activate) => {
match tab_to_activate {
Tab::Welcome => {
self.active_tab = Tab::Welcome
},
Tab::Home => {
self.active_tab = Tab::Home
},
Tab::CommingSoon => {
self.active_tab = Tab::CommingSoon
},
Tab::Debug => {
self.active_tab = Tab::Debug
}
}
}
}
self.storage.store(RESTORE_KEY, Json(&self.active_tab));
true
}
fn change(&mut self, props: Self::Properties) -> ShouldRender {
// if self.active_tab == Tab::Home
true
}
}
impl Renderable<TabNavigation> for TabNavigation {
fn view(&self) -> Html<Self> {
html! {
// WELCOME
let welcome_button = if let Tab::Welcome = self.active_tab {
html! {
<WelcomeButton onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::Welcome)) title="Welcome" class="active" />
// INSERT SECTION HERE
}
} else {
html! {
<WelcomeButton onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::Welcome)) title="Welcome" class="not-active" />
}
};
// HOME
let home_button = if let Tab::Home = self.active_tab {
html! {
<HomeButton onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::Home)) title="Home" class="active" />
}
} else {
html! {
<HomeButton onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::Home)) title="Home" class="not-active" />
}
};
// COMMING SOON
let comming_soon_button = if let Tab::CommingSoon = self.active_tab {
html! {
<CommingSoon onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::CommingSoon)) title="Comming Soon" class="active" />
}
} else {
html! {
<CommingSoon onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::CommingSoon)) title="Comming Soon" class="not-active" />
}
};
// DEBUG
let debug_button = if let Tab::Debug = self.active_tab {
html! {
<DebugButton onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::Debug)) title="Debug" class="active" />
}
} else {
html! {
<DebugButton onsignal=self.link.callback(|_| Msg::ChangeTab(Tab::Debug)) title="Debug" class="not-active" />
}
};
html! {
<>
{welcome_button}
{home_button}
{comming_soon_button}
{debug_button}
</>
}
}
}
}
I use "text/template" module.
I have struct like this to parse XML from Blogger
type Media struct {
ThumbnailUrl string `xml:"url,attr"`
}
type Entry struct {
ID string `xml:"id"`
Published Date `xml:"published"`
Updated Date `xml:"updated"`
Draft Draft `xml:"control>draft"`
Title string `xml:"title"`
Content string `xml:"content"`
Tags Tags `xml:"category"`
Author Author `xml:"author"`
Media Media `xml:"thumbnail"`
Extra string
}
Then I create Go Template like this
[image]
src = "{{ replace .Media.ThumbnailUrl 's72-c' 's1600' }}"
link = ""
thumblink = "{{ .Media.ThumbnailUrl }}"
alt = ""
title = ""
author = ""
license = ""
licenseLink = ""
The replace function not defined. I want to replace URL from {{ .Media.ThumbnailUrl }}
For example:
from this URL
https://2.bp.blogspot.com/-DEeRanrBa6s/WGWGwA2qW5I/AAAAAAAADg4/feGUc-g9rXc9B7hXpKr0ecG9UOMXU3_VQCK4B/s72-c/pemrograman%2Bjavascript%2B-%2Bpetanikode.png
To this URL
https://2.bp.blogspot.com/-DEeRanrBa6s/WGWGwA2qW5I/AAAAAAAADg4/feGUc-g9rXc9B7hXpKr0ecG9UOMXU3_VQCK4B/s1600/pemrograman%2Bjavascript%2B-%2Bpetanikode.png
You can write a helper view function like this
func replace(input, from,to string) string {
return strings.Replace(input,from,to, -1)
}
funcMap = template.FuncMap{
"replace": replace,
}
template := template.New("").Funcs(internalFuncMap)
and use the template to render the view.
code ref links
https://github.com/sairam/kinli/blob/master/template_funcs.go#L57-L59
https://github.com/sairam/kinli/blob/master/templates.go#L48
I'm trying to do validation on my form struct in a method that returns a bool, but I keep getting false even when it should be returning true..
If you look towards the end of the Validate method, you'll see I write validated := len(this.Errors) == 0 which should be making "validated" either true or false based on whether the Errors map has items or not, and then I return validated.
When I fill out my form accurately, there should be no errors yet I still get false when I should be getting true.
Can someone explain? Is this not how Go works?
form.go:
package models
import (
"../config"
"../util"
)
type Form struct {
Name string
Email string
Phone string
Message string
Thanks string
ErrorHandler
}
func (this *Form) Validate() bool {
this.Errors = make(map[string]string)
matched := util.MatchRegexp(".+#.+\\..+", this.Email)
if !util.IsEmpty(this.Email) {
if matched == false {
this.Errors["Email"] = config.EMAIL_INVALID
}
} else {
this.Errors["Email"] = config.EMAIL_EMPTY
}
if util.IsEmpty(this.Name) {
this.Errors["Name"] = config.NAME_EMPTY
}
if util.IsEmpty(this.Phone) {
this.Errors["Phone"] = config.PHONE_EMPTY
}
if util.IsEmpty(this.Message) {
this.Errors["Message"] = config.MESSAGE_EMPTY
}
validated := len(this.Errors) == 0
if validated {
this.Thanks = config.THANK_YOU
}
return validated
}
errorhandler.go:
package models
type ErrorHandler struct {
Errors map[string]string
}
func (this *ErrorHandler) HandleErr(err string) {
this.Errors = make(map[string]string)
this.Errors["Error"] = err
}
And this is where I try to call the Validate method -- in a function in my controller:
form := &models.Form{
Name: r.FormValue("name"),
Email: r.FormValue("email"),
Phone: r.FormValue("phone"),
Message: r.FormValue("message")}
if form.Validate() {
// This never runs because 'form.Validate()' is always false
}
I don't think the util.IsEmpty() is the culprit here.. just checks if the string is empty:
func IsEmpty(str string) bool {
return strings.TrimSpace(str) == ""
}
Any help would be appreciated!
It's best to debug this kind of problem with a log statement like:
log.Printf("form: %v", form)
before calling validate, so it's clear what the input data looks like.
Greetings, Philip
I've recently swapped out datastores and as a side-effect have had to change a struct field from template.HTML to string to be compatible with the marshaller/DB driver. This field, RenderedDesc, contains rendered HTML as passed through russross/blackfriday.
Previously I could just pass the whole struct into the template "as is" and call {{ .RenderedDesc }} in the template.
Because it's now a string, I've added a filter to convert it back on template render:
templates.go
func RenderUnsafe(s string) template.HTML {
return template.HTML(s)
}
template.FuncMap{
...
"unsafe": RenderUnsafe,
}
_content.tmpl
...
<div class="detail">
{{ .RenderedDesc | unsafe }}
</div>
...
Is there a better way to achieve this without having to use a filter at the template level? Short of re-writing marshalling logic from my DB driver (not on the cards) it looks like this is the simplest way to "store" strings but render raw HTML.
IMHO, the right way to do this is using a filter, like you are already doing. There are more ways to achieve the same, one of them is using tags and converting the struct in to a map[string]Interface{}. Because map fields can be reached in the same way that structs, your templates will remain unmodified.
Show me the code (playground):
package main
import (
"html/template"
"os"
"reflect"
)
var templates = template.Must(template.New("tmp").Parse(`
<html>
<head>
</head>
<body>
<h1>Hello</h1>
<div class="content">
Usafe Content = {{.Content}}
Safe Content = {{.Safe}}
Bool = {{.Bool}}
Num = {{.Num}}
Nested.Num = {{.Nested.Num}}
Nested.Bool = {{.Nested.Bool}}
</div>
</body>
</html>
`))
func asUnsafeMap(any interface{}) map[string]interface{} {
v := reflect.ValueOf(any)
if v.Kind() != reflect.Struct {
panic("asUnsafeMap invoked with a non struct parameter")
}
m := map[string]interface{}{}
for i := 0; i < v.NumField(); i++ {
value := v.Field(i)
if !value.CanInterface() {
continue
}
ftype := v.Type().Field(i)
if ftype.Tag.Get("unsafe") == "html" {
m[ftype.Name] = template.HTML(value.String())
} else {
m[ftype.Name] = value.Interface()
}
}
return m
}
func main() {
templates.ExecuteTemplate(os.Stdout, "tmp", asUnsafeMap(struct {
Content string `unsafe:"html"`
Safe string
Bool bool
Num int
Nested struct {
Num int
Bool bool
}
}{
Content: "<h2>Lol</h2>",
Safe: "<h2>Lol</h2>",
Bool: true,
Num: 10,
Nested: struct {
Num int
Bool bool
}{
Num: 9,
Bool: true,
},
}))
}
Output:
<html>
<head>
</head>
<body>
<h1>Hello</h1>
<div class="content">
Usafe Content = <h2>Lol</h2>
Safe Content = <h2>Lol</h2>
Bool = true
Num = 10
Nested.Num = 9
Nested.Bool = true
</div>
</body>
</html>
Note: the previous code doesn't work with nested structures, but it will be easy to add support for them. Also, every field tagged as unsafe will be treated as string.