Problem:
I have created a simple form, where there's an input field "num". After submission I want to show the value of num in the same input field, in other words want to retain the input in that field. If the value was set to 0 then I want to ignore that.
I can do it in several languages but I'm not sure about how to do it in Golang. My current template file has,
<input type="text" placeholder="foo" name="bar" value="{{if gt .N 0 }} {{.N}} {{end}} "/>
Server file contains:
data := &listOfReport {
R: r,
I: i,
N: n
}
listTmpl := template.Must(template.New("list_tmpl").Parse(string(report.Template["xxx.tmpl"])))
if err := listTmpl.Execute(w, data); err != nil {
http.Error(w, fmt.Sprintf("Error rendering template %v", err), 500)
}
Another thought is to make N a string so make it '' or value in the server file. But that actually spoils the variable's name/purpose.
Is there any better way to do it? Is ther any better way to access GET parameters directly from template? Please note that the value of N is originally got from a GET variable.
*This code is not tested
There is no standard/builtin way to get any request parameters from within a template, you'll have to put it into your data. (You could write a function which does this for you, but that will result in an ugly hack.)
I don't see what's wrong with your solution.
I take a similar approach, but use structs.
type SignupForm struct {
Name string
Email string
Etcera bool
}
// Type alias
type M map[string]interface{}
...
// In the handler that accepts your form
err := r.ParseForm()
if err != nil {
// handle error
}
signup := SignupForm{}
err := decoder.Decode(signup, r.PostForm)
if err != nil {
// handle error
}
// Store the 'saved' form contents somewhere temporary -
// e.g.
// - cookies (keep in mind the 4K browser limit)
// - server side sessions (Redis; how I do it)
// - db
// In the handler that renders your form
err := template.ExecuteTemplate(w, "form.html", M{
"form": signup,
"csrfToken": csrfToken,
// and so on...
})
Note that wherever you store the form data, make sure it is temporary. Server side sessions are ideal as you can have them expire (if you don't want to delete them manually).
Related
I was able to use the CollectionGroup to access all the subCollection documents (records) that satisfy a condition. Then I was able to iterate in a loop to delete the subCollection documents. The problem, although it works perfectly but is an hack. Is there a better way to delete subcollections in Firestore using Golang?
it := clientdb.CollectionGroup("mychildSubcollection").Where(...mycondition).OrderBy("myfield", firestore.Desc).Documents(context.Background())
for {
doc, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
// return err
}
// Strucure of the doc.Ref is --> &{0xc0000d6788 projects/myproj/databases/(default)/documents/myparentCollection/Ki8sr65sKIoZaCviCp/mychildSubcollection/JwvKbuyRTGx5wZaCviCp myparentCollection/Ki8sr65sKIoZaCviCp/mychildSubcollection/JwvKbuyRTGx5wZaCviCp JwvKbuyRTGx5wZaCviCp}
// fmt.Println(doc.Ref.ID)
// fmt.Println(doc.Ref.Path)
// fmt.Println(doc.Ref.Parent.Path)
// fmt.Println(doc.Ref.Parent.ID)
path1 := doc.Ref.Parent.Path
path2 := path1[0: strings.LastIndex(path1, "myparentCollection")]
path3 := strings.Replace(path1, path2, "", -1)
clientdb.Collection(path3).Doc(doc.Ref.ID).Delete(context.Background()) // Regular collection command, to delete the subcollection
}
At least to make it a less hack, this may also help -> As you see the doc.Ref provides three fields showing the complete path [doc.Ref.Path or doc.Ref.Parent.Path] the subcollection document id (doc.Ref.ID), how to access the middle field in the structure: "myparentCollection/Ki8sr65sKIoZaCviCp/mychildSubcollection/JwvKbuyRTGx5wZaCviCp"
Thanks!
The above is accepted as solution. The only comment I am adding is that if there is an better way to extract the path for the collection, it will be more generic. As you see I am using the actual collection name [myparentCollection] to extract the path. Works great, but something generic would be better.
now := time.Now() // start deleting old ones, even ones that still have one second left to expire.
it := clientdb.CollectionGroup("mychildSubcollection").Where("expireafter", "<", now.Add(-1*time.Second)).OrderBy("myfield", firestore.Desc).Documents(context.Background())
for {
doc, err := it.Next()
if err == iterator.Done {
break
}
if err != nil {
// return err
}
// Strucure of the doc.Ref is --> &{0xc0000d6788 projects/myproj/databases/(default)/documents/myparentCollection/Ki8sr65sKIoZaCviCp/mychildSubcollection/JwvKbuyRTGx5wZaCviCp myparentCollection/Ki8sr65sKIoZaCviCp/mychildSubcollection/JwvKbuyRTGx5wZaCviCp JwvKbuyRTGx5wZaCviCp}
// fmt.Println(doc.Ref.ID)
// fmt.Println(doc.Ref.Path)
// fmt.Println(doc.Ref.Parent.Path)
// fmt.Println(doc.Ref.Parent.ID)
// using some logic with strings below to get (extract) the collection path example: myparentCollection/Ki8sr65sKIoZaCviCp/mychildSubcollection, so the delete can use it and delete the particular document under the sub collection.
path1 := doc.Ref.Parent.Path
path2 := path1[0: strings.LastIndex(path1, "myparentCollection")]
path3 := strings.Replace(path1, path2, "", -1)
clientdb.Collection(path3).Doc(doc.Ref.ID).Delete(context.Background()) // Regular collection command, to delete the subcollection
}
I want to dynamically populate my internal struct, for an atomic insert. I am new to go so pointers and referencing them is something that I am still learning. I can not figure out why this for each loop is putting the same fields in twice. I tried removing the '&' then I get a cannot use type as *type error, I checked to make sure my loop was hitting every object in the tradeArray, and it is. It looks like it is overwriting the object before it with the last one it loops over. How can I fix this?
func createTrade(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var tradeArray []Trade
if err := json.NewDecoder(r.Body).Decode(&tradeArray); err != nil {
e := Error{Message: "Bad Request - Improper Types Passed"}
w.WriteHeader(http.StatusBadRequest)
_ = json.NewEncoder(w).Encode(e)
return
}
for _, trade := range tradeArray {
internal := InternalTrade{
Id: strconv.Itoa(rand.Intn(1000000)),
Trade: &trade,
}
submit := TradeSubmitted{
TradeId: internal.Id,
ClientTradeId: trade.ClientTradeId ,
}
submitArray = append(submitArray, submit)
trades = append(trades, internal)
}
if err := json.NewEncoder(w).Encode(submitArray); err != nil {
e := Error{Message:"Internal Server Error"}
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(e)
return
}
}
edit: I was able to fix my problem by creating a new variable to hold the trade and referencing that variable in the struct creation. I am not sure how this is different that what I was doing above with just referencing the "trade" if someone could explain that I would greatly appreciate it.
for _, trade := range tradeArray {
p := trade
internal := InternalTrade{
Id: strconv.Itoa(rand.Intn(1000000)),
Trade: &p,
}
submit := TradeSubmitted{
TradeId: internal.Id,
ClientTradeId: trade.ClientTradeId ,
}
submitArray = append(submitArray, submit)
trades = append(trades, internal)
}
Let's look at just these parts:
var tradeArray []Trade
// code that fills in `tradeArray` -- correct, and omitted here
for _, trade := range tradeArray {
internal := InternalTrade{
Id: strconv.Itoa(rand.Intn(1000000)),
Trade: &trade,
}
submit := TradeSubmitted{
TradeId: internal.Id,
ClientTradeId: trade.ClientTradeId ,
}
submitArray = append(submitArray, submit)
trades = append(trades, internal)
}
This for loop, as you have seen, doesn't work the way you want. Here's a variant of it that's kind of similar, except that the variable trade has scope that extends beyond the for loop:
var trade Trade
for i := range tradeArray {
trade = tradeArray[i]
internal := InternalTrade{
Id: strconv.Itoa(rand.Intn(1000000)),
Trade: &trade,
}
// do correct stuff with `internal`
}
Note that each internal object points to a single, shared trade variable, whose value gets overwritten on each trip through the loop. The result is that they all point to the one from the last trip through the loop.
Your fix is itself OK: each trip through the loop, you make a new (different) p variable, and use &p, so that each internal.Trade has a different pointer to a different copy. You could also just do trade := trade inside the loop, to create a new unique trade variable. However, in this particular case, it may make the most sense to rewrite the loop this way:
for i := range tradeArray {
internal := InternalTrade{
Id: strconv.Itoa(rand.Intn(1000000)),
Trade: &tradeArray[i],
}
// do correct stuff with `internal`
}
That is, you already have len(tradeArray) different Trade objects: the slice header tradeArray gives you access to each tradeArray[i] instance, stored in the underlying array. You can just point to those directly.
There are various advantages and disadvantages to this approach. The big advantage is that you don't re-copy each trade at all: you just use the ones from the array that the slice header covers, that was allocated inside the json Decode function somewhere. The big disadvantage is that this underlying array cannot be garbage-collected as long as you retain any pointer to any of its elements. That disadvantage may have no cost at all, depending on the structure of the remaining code, but if it is a disadvantage, consider declaring tradeArray as:
var tradeArray []*Trade
so that the json Decode function allocates each one separately, and you can point to them one at a time without forcing the retention of the entire collection.
How do I append output from a twitter search to the field Data in the SearchTwitterOutput{} struct.
Thanks!
I am using a twitter library to search twitter base on a query input. The search returns an array of strings(I believe), I am able to fmt.println the data but I need the data as a struct.
type SearchTwitterOutput struct {
Data string
}
func (SearchTwitter) execute(input SearchTwitterInput) (*SearchTwitterOutput, error) {
credentials := Credentials{
AccessToken: input.AccessToken,
AccessTokenSecret: input.AccessTokenSecret,
ConsumerKey: input.ConsumerKey,
ConsumerSecret: input.ConsumerSecret,
}
client, err := GetUserClient(&credentials)
if err != nil {
return nil, err
}
// search through the tweet and returns a
search, _ , err := client.Search.Tweets(&twitter.SearchTweetParams{
Query: input.Text,
})
if err != nil {
println("PANIC")
panic(err.Error())
return &SearchTwitterOutput{}, err
}
for k, v := range search.Statuses {
fmt.Printf("Tweet %d - %s\n", k, v.Text)
}
return &SearchTwitterOutput{
Data: "test", //data is a string for now it can be anything
}, nil
}
//Data field is a string type for now it can be anything
//I use "test" as a placeholder, bc IDK...
Result from fmt.Printf("Tweet %d - %s\n", k, v.Text):
Tweet 0 - You know I had to do it to them! #JennaJulien #Jenna_Marbles #juliensolomita #notjulen Got my first hydroflask ever…
Tweet 1 - RT #brenna_hinshaw: I was in J2 today and watched someone fill their hydroflask with vanilla soft serve... what starts here changes the wor…
Tweet 2 - I miss my hydroflask :(
This is my second week working with go and new to development. Any help would be great.
It doesn't look like the client is just returning you a slice of strings. The range syntax you're using (for k, v := range search.Statuses) returns two values for each iteration, the index in the slice (in this case k), and the object from the slice (in this case v). I don't know the type of search.Statuses - but I know that strings don't have a .Text field or method, which is how you're printing v currently.
To your question:
Is there any particular reason to return just a single struct with a Data field rather than directly returning the output of the twitter client?
Your function signature could look like this instead:
func (SearchTwitter) execute(input SearchTwitterInput) ([]<client response struct>, error)
And then you could operate on the text in those objects in wherever this function was called.
If you're dead-set on placing the data in your own struct, you could return a slice of them ([]*SearchTwitterOutput), in which case you could build a single SearchTwitterOutput in the for loop you're currently printing the tweets in and append it to the output list. That might look like this:
var output []*SearchTwitterOutput
for k, v := range search.Statuses {
fmt.Printf("Tweet %d - %s\n", k, v.Text)
output = append(output, &SearchTwitterOutput{
Data: v.Text,
})
}
return output, nil
But if your goal really is to return all of the results concatenated together and placed inside a single struct, I would suggest building a slice of strings (containing the text you want), and then joining them with the delimiter of your choosing. Then you could place the single output string in your return object, which might look something like this:
var outputStrings []string
for k, v := range search.Statuses {
fmt.Printf("Tweet %d - %s\n", k, v.Text)
outputStrings = append(outputStrings, v.Text)
}
output = strings.Join(outputStrings, ",")
return &SearchTwitterOutput{
Data: output,
}, nil
Though I would caution, it might be tricky to find a delimiter that will never show up in a tweet..
I'm new to go and still confused about pointers but I have followed the instructions for querying multiple rows but the result I get back is series of memory addresses instead of actual values.
This same structure, minus the rows.Next() works just fine for a single user so I'm confused as to the origin of the problem here.
Ultimately I'm trying to use the results of the function in a template but I'm trying to figure out the structure of it so I can range it in my HTML.
For example, if I try to run the code below, I get something like: &{[0xc... 0xc... 0xc...]}
type User struct {
Id int `json:"int"`
Name string `json:"name"`
Role string `json:"role"`
}
type Users struct {
Users []*User
}
func getUsers(company string) *Users {
users := Users{}
rows, err := db.Query("SELECT Id, Name, Role...")
// Check err
defer rows.Close()
for rows.Next() {
user := &User{}
err = rows.Scan(&user.Id, &user.Name, &user.Role)
// Check err
users.Users = append(users.Users, user)
}
err = rows.Err()
// Check err
return &users
}
This is how I'm attempting to use the function
func userView(w http.ResponseWriter, r *http.Request) {
res := getUsers("test") // Should return 3 results
fmt.Println(res.Users)
}
The problem isn't in your fetching of the data, it's in your display of the data. fmt.Println() prints memory addresses when given pointers--so it's behaving exactly as expected.
If you instead do:
fmt.Printf("%+v", res.Users)
you'll get a different result, probably closer to what you expect.
If you're planning to use a template, then you should do so--your template should be able to access the fields of each User just fine.
But the short answer is: Your testing method is invalid.
Type Users is a slice of pointers. If you print the return value of getUsers it looks like a bunch of memory addresses. This is OK.
If you want to print something more meaningful, write a String() method for Users in which you dereference each pointer and build a string containing struct fields.
I have spent a bit of time attempting to do this, and I think I need a global array (not slice), and I want to pass it as a pointer, not by value. The function receiving the pointer needs to test for nil, and if nil, read the array from disk, using eg: "baForm, oOserr = ioutil.ReadFile(sFormName)". The calling function may pass either a global array or an array local to the calling function which I presume will be garbage collected.
The reason for doing this is that I want a standard function to read the forms from disk, and often-used forms are stored globally. Despite whether some may think there is a better way, I still want to know how to achieve this ie: a) have global or local array, b) not pass by value, c) The global arrays will be read only once from disk and the local arrays will be read each time the function is called. TIA.
From reading your description, I can't see why passing a pointer to an array is any way better than passing a slice -- but it's up to you.
You can pass a pointer just like you do in C -- attach an asterisk (*) to the declaration, and perpend an ampersand (&) to the value when you call the function.
Just remember that in Go, the array size is part of its type. This means that your function declaration will have the array size embedded into it, so you can't call the function using an array of any different size. This reason alone is generally enough to warrant using a slice instead of an array.
Here's a sample program that maintains a dynamic forms buffer based on use count. If the ReadForm function finds a form, it returns the address of the form and a nil error.
package main
import (
"fmt"
"io/ioutil"
"math"
"os"
"sync"
)
type Form struct {
Name string
useCount int64
Data []byte
}
// The capacity of the forms buffer.
const formsCap = 2
// The forms buffer.
var (
forms = make(map[string]*Form, formsCap)
formsLock sync.RWMutex
)
func ReadForm(name string) (form *Form, err os.Error) {
formsLock.RLock()
form, ok := forms[name]
formsLock.RUnlock()
if !ok {
form = &Form{name, 0, nil}
}
if form.Data == nil {
data, err := ioutil.ReadFile(name + ".form")
if err != nil {
return nil, err
}
form = &Form{name, 0, data}
formsLock.Lock()
if len(forms) >= formsCap {
minForm := &Form{useCount: math.MaxInt64}
for i, f := range forms {
if f.useCount < minForm.useCount {
minForm = f
}
}
minform.Data = nil
}
forms[name] = form
formsLock.Unlock()
}
form.useCount++
return form, nil
}
func main() {
// form files are named name.form e.g. form1.form
for _, name := range []string{"form1", "form2", "form3"} {
f, err := ReadForm(name)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(f.Data))
}
}
fmt.Println(len(forms), forms)
}
EDIT: Map operations are not atomic. Revise the sample program to use a mutex for concurrent access to the forms map.