{"action":"opened","issue":{"url":"https://api.github.com/repos/astaxie/beego/issues/2516","repository_url":"https://api.github.com/repos/astaxie/beego","labels_url":"https://api.github.com/repos/astaxie/beego/issues/2516/labels{/name}","comments_url":"https://api.github.com/repos/astaxie/beego/issues/2516/comments","events_url":"https://api.github.com/repos/astaxie/beego/issues/2516/events","html_url":"https://github.com/astaxie/beego/issues/2516","id":215328845,"number":2516,"title":"how to exec func in form init for select options","user":{"login":"xurwxj","id":683421,"avatar_url":"https://avatars0.githubusercontent.com/u/683421?v=3","gravatar_id":"","url":"https://api.github.com/users/xurwxj","html_url":"https://github.com/xurwxj","followers_url":"https://api.github.com/users/xurwxj/followers","following_url":"https://api.github.com/users/xurwxj/following{/other_user}","gists_url":"https://api.github.com/users/xurwxj/gists{/gist_id}","starred_url":"https://api.github.com/users/xurwxj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xurwxj/subscriptions","organizations_url":"https://api.github.com/users/xurwxj/orgs","repos_url":"https://api.github.com/users/xurwxj/repos","events_url":"https://api.github.com/users/xurwxj/events{/privacy}","received_events_url":"https://api.github.com/users/xurwxj/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2017-03-20T04:35:26Z","updated_at":"2017-03-20T04:35:26Z","closed_at":null,"body":"Please answer these questions before submitting your issue. Thanks!\r\n\r\n1. What version of Go and beego are you using (`bee version`)?\r\n1.8\r\n\r\n2. What operating system and processor architecture are you using (`go env`)?\r\n\r\n1.8\r\nmac\r\n\r\n3. What did you do?\r\nIf possible, provide a recipe for reproducing the error.\r\nA complete runnable program is good.\r\nform define:\r\n```\r\ntype ArticleForm struct {\r\n\tName     string     `form:\"Name,text,名 称：\" required:\"true\" pattern:\"^[A-Za-z0-9\\u4e00-\\u9fa5]{1,1024}$\" err:\"名称不能已经存在且必须是字母、数字或汉字，不区分大小写，长度在1～1024个\" valid:\"Required;MaxSize(1024)\"`\r\n\tCategory []Category `form:\"Category,multiselect,分 类：\" class:\"multis\" required:\"true\" err:\"分类必须至少选择1个\" valid:\"Required\" optionqs:\"models.GetCategoryOptions\"`\r\n\tContent  string     `form:\"Content,textarea,内 容：\" class:\"wysiwg_area\" required:\"true\" err:\"内容不能为空\" valid:\"Required\"`\r\n\tTags     []Tags     `form:\"Tags,multiselect,标 签：\" class:\"multis_create\" optionqs:\"ssss\"`\r\n}\r\n```\r\nrender form(templatefunc.go changed as following):\r\n```\r\n// Copyright 2014 beego Author. All Rights Reserved.\r\n//\r\n// Licensed under the Apache License, Version 2.0 (the \"License\");\r\n// you may not use this file except in compliance with the License.\r\n// You may obtain a copy of the License at\r\n//\r\n//      http://www.apache.org/licenses/LICENSE-2.0\r\n//\r\n// Unless required by applicable law or agreed to in writing, software\r\n// distributed under the License is distributed on an \"AS IS\" BASIS,\r\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n// See the License for the specific language governing permissions and\r\n// limitations under the License.\r\n\r\npackage beego\r\n\r\nimport (\r\n\t\"errors\"\r\n\t\"fmt\"\r\n\t\"html/template\"\r\n\t\"net/url\"\r\n\t\"reflect\"\r\n\t\"regexp\"\r\n\t\"strconv\"\r\n\t\"strings\"\r\n\t\"time\"\r\n)\r\n\r\n// Substr returns the substr from start to length.\r\nfunc Substr(s string, start, length int) string {\r\n\tbt := []rune(s)\r\n\tif start < 0 {\r\n\t\tstart = 0\r\n\t}\r\n\tif start > len(bt) {\r\n\t\tstart = start % len(bt)\r\n\t}\r\n\tvar end int\r\n\tif (start + length) > (len(bt) - 1) {\r\n\t\tend = len(bt)\r\n\t} else {\r\n\t\tend = start + length\r\n\t}\r\n\treturn string(bt[start:end])\r\n}\r\n\r\n// HTML2str returns escaping text convert from html.\r\nfunc HTML2str(html string) string {\r\n\tsrc := string(html)\r\n\r\n\tre, _ := regexp.Compile(\"\\\\<[\\\\S\\\\s]+?\\\\>\")\r\n\tsrc = re.ReplaceAllStringFunc(src, strings.ToLower)\r\n\r\n\t//remove STYLE\r\n\tre, _ = regexp.Compile(\"\\\\<style[\\\\S\\\\s]+?\\\\</style\\\\>\")\r\n\tsrc = re.ReplaceAllString(src, \"\")\r\n\r\n\t//remove SCRIPT\r\n\tre, _ = regexp.Compile(\"\\\\<script[\\\\S\\\\s]+?\\\\</script\\\\>\")\r\n\tsrc = re.ReplaceAllString(src, \"\")\r\n\r\n\tre, _ = regexp.Compile(\"\\\\<[\\\\S\\\\s]+?\\\\>\")\r\n\tsrc = re.ReplaceAllString(src, \"\\n\")\r\n\r\n\tre, _ = regexp.Compile(\"\\\\s{2,}\")\r\n\tsrc = re.ReplaceAllString(src, \"\\n\")\r\n\r\n\treturn strings.TrimSpace(src)\r\n}\r\n\r\n// DateFormat takes a time and a layout string and returns a string with the formatted date. Used by the template parser as \"dateformat\"\r\nfunc DateFormat(t time.Time, layout string) (datestring string) {\r\n\tdatestring = t.Format(layout)\r\n\treturn\r\n}\r\n\r\n// DateFormat pattern rules.\r\nvar datePatterns = []string{\r\n\t// year\r\n\t\"Y\", \"2006\", // A full numeric representation of a year, 4 digits   Examples: 1999 or 2003\r\n\t\"y\", \"06\", //A two digit representation of a year   Examples: 99 or 03\r\n\r\n\t// month\r\n\t\"m\", \"01\", // Numeric representation of a month, with leading zeros 01 through 12\r\n\t\"n\", \"1\", // Numeric representation of a month, without leading zeros   1 through 12\r\n\t\"M\", \"Jan\", // A short textual representation of a month, three letters Jan through Dec\r\n\t\"F\", \"January\", // A full textual representation of a month, such as January or March   January through December\r\n\r\n\t// day\r\n\t\"d\", \"02\", // Day of the month, 2 digits with leading zeros 01 to 31\r\n\t\"j\", \"2\", // Day of the month without leading zeros 1 to 31\r\n\r\n\t// week\r\n\t\"D\", \"Mon\", // A textual representation of a day, three letters Mon through Sun\r\n\t\"l\", \"Monday\", // A full textual representation of the day of the week  Sunday through Saturday\r\n\r\n\t// time\r\n\t\"g\", \"3\", // 12-hour format of an hour without leading zeros    1 through 12\r\n\t\"G\", \"15\", // 24-hour format of an hour without leading zeros   0 through 23\r\n\t\"h\", \"03\", // 12-hour format of an hour with leading zeros  01 through 12\r\n\t\"H\", \"15\", // 24-hour format of an hour with leading zeros  00 through 23\r\n\r\n\t\"a\", \"pm\", // Lowercase Ante meridiem and Post meridiem am or pm\r\n\t\"A\", \"PM\", // Uppercase Ante meridiem and Post meridiem AM or PM\r\n\r\n\t\"i\", \"04\", // Minutes with leading zeros    00 to 59\r\n\t\"s\", \"05\", // Seconds, with leading zeros   00 through 59\r\n\r\n\t// time zone\r\n\t\"T\", \"MST\",\r\n\t\"P\", \"-07:00\",\r\n\t\"O\", \"-0700\",\r\n\r\n\t// RFC 2822\r\n\t\"r\", time.RFC1123Z,\r\n}\r\n\r\n// DateParse Parse Date use PHP time format.\r\nfunc DateParse(dateString, format string) (time.Time, error) {\r\n\treplacer := strings.NewReplacer(datePatterns...)\r\n\tformat = replacer.Replace(format)\r\n\treturn time.ParseInLocation(format, dateString, time.Local)\r\n}\r\n\r\n// Date takes a PHP like date func to Go's time format.\r\nfunc Date(t time.Time, format string) string {\r\n\treplacer := strings.NewReplacer(datePatterns...)\r\n\tformat = replacer.Replace(format)\r\n\treturn t.Format(format)\r\n}\r\n\r\n// Compare is a quick and dirty comparison function. It will convert whatever you give it to strings and see if the two values are equal.\r\n// Whitespace is trimmed. Used by the template parser as \"eq\".\r\nfunc Compare(a, b interface{}) (equal bool) {\r\n\tequal = false\r\n\tif strings.TrimSpace(fmt.Sprintf(\"%v\", a)) == strings.TrimSpace(fmt.Sprintf(\"%v\", b)) {\r\n\t\tequal = true\r\n\t}\r\n\treturn\r\n}\r\n\r\n// CompareNot !Compare\r\nfunc CompareNot(a, b interface{}) (equal bool) {\r\n\treturn !Compare(a, b)\r\n}\r\n\r\n// NotNil the same as CompareNot\r\nfunc NotNil(a interface{}) (isNil bool) {\r\n\treturn CompareNot(a, nil)\r\n}\r\n\r\n// GetConfig get the Appconfig\r\nfunc GetConfig(returnType, key string, defaultVal interface{}) (value interface{}, err error) {\r\n\tswitch returnType {\r\n\tcase \"String\":\r\n\t\tvalue = AppConfig.String(key)\r\n\tcase \"Bool\":\r\n\t\tvalue, err = AppConfig.Bool(key)\r\n\tcase \"Int\":\r\n\t\tvalue, err = AppConfig.Int(key)\r\n\tcase \"Int64\":\r\n\t\tvalue, err = AppConfig.Int64(key)\r\n\tcase \"Float\":\r\n\t\tvalue, err = AppConfig.Float(key)\r\n\tcase \"DIY\":\r\n\t\tvalue, err = AppConfig.DIY(key)\r\n\tdefault:\r\n\t\terr = errors.New(\"Config keys must be of type String, Bool, Int, Int64, Float, or DIY\")\r\n\t}\r\n\r\n\tif err != nil {\r\n\t\tif reflect.TypeOf(returnType) != reflect.TypeOf(defaultVal) {\r\n\t\t\terr = errors.New(\"defaultVal type does not match returnType\")\r\n\t\t} else {\r\n\t\t\tvalue, err = defaultVal, nil\r\n\t\t}\r\n\t} else if reflect.TypeOf(value).Kind() == reflect.String {\r\n\t\tif value == \"\" {\r\n\t\t\tif reflect.TypeOf(defaultVal).Kind() != reflect.String {\r\n\t\t\t\terr = errors.New(\"defaultVal type must be a String if the returnType is a String\")\r\n\t\t\t} else {\r\n\t\t\t\tvalue = defaultVal.(string)\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\treturn\r\n}\r\n\r\n// Str2html Convert string to template.HTML type.\r\nfunc Str2html(raw string) template.HTML {\r\n\treturn template.HTML(raw)\r\n}\r\n\r\n// Htmlquote returns quoted html string.\r\nfunc Htmlquote(src string) string {\r\n\t//HTML编码为实体符号\r\n\t/*\r\n\t   Encodes `text` for raw use in HTML.\r\n\t       >>> htmlquote(\"<'&\\\\\">\")\r\n\t       '&lt;&#39;&amp;&quot;&gt;'\r\n\t*/\r\n\r\n\ttext := string(src)\r\n\r\n\ttext = strings.Replace(text, \"&\", \"&amp;\", -1) // Must be done first!\r\n\ttext = strings.Replace(text, \"<\", \"&lt;\", -1)\r\n\ttext = strings.Replace(text, \">\", \"&gt;\", -1)\r\n\ttext = strings.Replace(text, \"'\", \"&#39;\", -1)\r\n\ttext = strings.Replace(text, \"\\\"\", \"&quot;\", -1)\r\n\ttext = strings.Replace(text, \"“\", \"&ldquo;\", -1)\r\n\ttext = strings.Replace(text, \"”\", \"&rdquo;\", -1)\r\n\ttext = strings.Replace(text, \" \", \"&nbsp;\", -1)\r\n\r\n\treturn strings.TrimSpace(text)\r\n}\r\n\r\n// Htmlunquote returns unquoted html string.\r\nfunc Htmlunquote(src string) string {\r\n\t//实体符号解释为HTML\r\n\t/*\r\n\t   Decodes `text` that's HTML quoted.\r\n\t       >>> htmlunquote('&lt;&#39;&amp;&quot;&gt;')\r\n\t       '<\\\\'&\">'\r\n\t*/\r\n\r\n\t// strings.Replace(s, old, new, n)\r\n\t// 在s字符串中，把old字符串替换为new字符串，n表示替换的次数，小于0表示全部替换\r\n\r\n\ttext := string(src)\r\n\ttext = strings.Replace(text, \"&nbsp;\", \" \", -1)\r\n\ttext = strings.Replace(text, \"&rdquo;\", \"”\", -1)\r\n\ttext = strings.Replace(text, \"&ldquo;\", \"“\", -1)\r\n\ttext = strings.Replace(text, \"&quot;\", \"\\\"\", -1)\r\n\ttext = strings.Replace(text, \"&#39;\", \"'\", -1)\r\n\ttext = strings.Replace(text, \"&gt;\", \">\", -1)\r\n\ttext = strings.Replace(text, \"&lt;\", \"<\", -1)\r\n\ttext = strings.Replace(text, \"&amp;\", \"&\", -1) // Must be done last!\r\n\r\n\treturn strings.TrimSpace(text)\r\n}\r\n\r\n// URLFor returns url string with another registered controller handler with params.\r\n//\tusage:\r\n//\r\n//\tURLFor(\".index\")\r\n//\tprint URLFor(\"index\")\r\n//  router /login\r\n//\tprint URLFor(\"login\")\r\n//\tprint URLFor(\"login\", \"next\",\"/\"\")\r\n//  router /profile/:username\r\n//\tprint UrlFor(\"profile\", \":username\",\"John Doe\")\r\n//\tresult:\r\n//\t/\r\n//\t/login\r\n//\t/login?next=/\r\n//\t/user/John%20Doe\r\n//\r\n//  more detail http://beego.me/docs/mvc/controller/urlbuilding.md\r\nfunc URLFor(endpoint string, values ...interface{}) string {\r\n\treturn BeeApp.Handlers.URLFor(endpoint, values...)\r\n}\r\n\r\n// AssetsJs returns script tag with src string.\r\nfunc AssetsJs(src string) template.HTML {\r\n\ttext := string(src)\r\n\r\n\ttext = \"<script src=\\\"\" + src + \"\\\"></script>\"\r\n\r\n\treturn template.HTML(text)\r\n}\r\n\r\n// AssetsCSS returns stylesheet link tag with src string.\r\nfunc AssetsCSS(src string) template.HTML {\r\n\ttext := string(src)\r\n\r\n\ttext = \"<link href=\\\"\" + src + \"\\\" rel=\\\"stylesheet\\\" />\"\r\n\r\n\treturn template.HTML(text)\r\n}\r\n\r\n// ParseForm will parse form values to struct via tag.\r\n// Support for anonymous struct.\r\nfunc parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) error {\r\n\tfor i := 0; i < objT.NumField(); i++ {\r\n\t\tfieldV := objV.Field(i)\r\n\t\tif !fieldV.CanSet() {\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tfieldT := objT.Field(i)\r\n\t\tif fieldT.Anonymous && fieldT.Type.Kind() == reflect.Struct {\r\n\t\t\terr := parseFormToStruct(form, fieldT.Type, fieldV)\r\n\t\t\tif err != nil {\r\n\t\t\t\treturn err\r\n\t\t\t}\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\ttags := strings.Split(fieldT.Tag.Get(\"form\"), \",\")\r\n\t\tvar tag string\r\n\t\tif len(tags) == 0 || len(tags[0]) == 0 {\r\n\t\t\ttag = fieldT.Name\r\n\t\t} else if tags[0] == \"-\" {\r\n\t\t\tcontinue\r\n\t\t} else {\r\n\t\t\ttag = tags[0]\r\n\t\t}\r\n\r\n\t\tvalue := form.Get(tag)\r\n\t\tif len(value) == 0 {\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tswitch fieldT.Type.Kind() {\r\n\t\tcase reflect.Bool:\r\n\t\t\tif strings.ToLower(value) == \"on\" || strings.ToLower(value) == \"1\" || strings.ToLower(value) == \"yes\" {\r\n\t\t\t\tfieldV.SetBool(true)\r\n\t\t\t\tcontinue\r\n\t\t\t}\r\n\t\t\tif strings.ToLower(value) == \"off\" || strings.ToLower(value) == \"0\" || strings.ToLower(value) == \"no\" {\r\n\t\t\t\tfieldV.SetBool(false)\r\n\t\t\t\tcontinue\r\n\t\t\t}\r\n\t\t\tb, err := strconv.ParseBool(value)\r\n\t\t\tif err != nil {\r\n\t\t\t\treturn err\r\n\t\t\t}\r\n\t\t\tfieldV.SetBool(b)\r\n\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\r\n\t\t\tx, err := strconv.ParseInt(value, 10, 64)\r\n\t\t\tif err != nil {\r\n\t\t\t\treturn err\r\n\t\t\t}\r\n\t\t\tfieldV.SetInt(x)\r\n\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:\r\n\t\t\tx, err := strconv.ParseUint(value, 10, 64)\r\n\t\t\tif err != nil {\r\n\t\t\t\treturn err\r\n\t\t\t}\r\n\t\t\tfieldV.SetUint(x)\r\n\t\tcase reflect.Float32, reflect.Float64:\r\n\t\t\tx, err := strconv.ParseFloat(value, 64)\r\n\t\t\tif err != nil {\r\n\t\t\t\treturn err\r\n\t\t\t}\r\n\t\t\tfieldV.SetFloat(x)\r\n\t\tcase reflect.Interface:\r\n\t\t\tfieldV.Set(reflect.ValueOf(value))\r\n\t\tcase reflect.String:\r\n\t\t\tfieldV.SetString(value)\r\n\t\tcase reflect.Struct:\r\n\t\t\tswitch fieldT.Type.String() {\r\n\t\t\tcase \"time.Time\":\r\n\t\t\t\tformat := time.RFC3339\r\n\t\t\t\tif len(tags) > 1 {\r\n\t\t\t\t\tformat = tags[1]\r\n\t\t\t\t}\r\n\t\t\t\tt, err := time.ParseInLocation(format, value, time.Local)\r\n\t\t\t\tif err != nil {\r\n\t\t\t\t\treturn err\r\n\t\t\t\t}\r\n\t\t\t\tfieldV.Set(reflect.ValueOf(t))\r\n\t\t\t}\r\n\t\tcase reflect.Slice:\r\n\t\t\tif fieldT.Type == sliceOfInts {\r\n\t\t\t\tformVals := form[tag]\r\n\t\t\t\tfieldV.Set(reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(int(1))), len(formVals), len(formVals)))\r\n\t\t\t\tfor i := 0; i < len(formVals); i++ {\r\n\t\t\t\t\tval, err := strconv.Atoi(formVals[i])\r\n\t\t\t\t\tif err != nil {\r\n\t\t\t\t\t\treturn err\r\n\t\t\t\t\t}\r\n\t\t\t\t\tfieldV.Index(i).SetInt(int64(val))\r\n\t\t\t\t}\r\n\t\t\t} else if fieldT.Type == sliceOfStrings {\r\n\t\t\t\tformVals := form[tag]\r\n\t\t\t\tfieldV.Set(reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(\"\")), len(formVals), len(formVals)))\r\n\t\t\t\tfor i := 0; i < len(formVals); i++ {\r\n\t\t\t\t\tfieldV.Index(i).SetString(formVals[i])\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn nil\r\n}\r\n\r\n// ParseForm will parse form values to struct via tag.\r\nfunc ParseForm(form url.Values, obj interface{}) error {\r\n\tobjT := reflect.TypeOf(obj)\r\n\tobjV := reflect.ValueOf(obj)\r\n\tif !isStructPtr(objT) {\r\n\t\treturn fmt.Errorf(\"%v must be  a struct pointer\", obj)\r\n\t}\r\n\tobjT = objT.Elem()\r\n\tobjV = objV.Elem()\r\n\r\n\treturn parseFormToStruct(form, objT, objV)\r\n}\r\n\r\nvar sliceOfInts = reflect.TypeOf([]int(nil))\r\nvar sliceOfStrings = reflect.TypeOf([]string(nil))\r\n\r\nvar unKind = map[reflect.Kind]bool{\r\n\treflect.Uintptr:    true,\r\n\treflect.Complex64:  true,\r\n\treflect.Complex128: true,\r\n\treflect.Array:      true,\r\n\treflect.Chan:       true,\r\n\treflect.Func:       true,\r\n\treflect.Map:        true,\r\n\treflect.Ptr:        true,\r\n\t// reflect.Slice:         true,\r\n\treflect.Struct:        true,\r\n\treflect.UnsafePointer: true,\r\n}\r\n\r\n// RenderForm will render object to form html.\r\n// obj must be a struct pointer.\r\nfunc RenderForm(obj interface{}) template.HTML {\r\n\tobjT := reflect.TypeOf(obj)\r\n\tobjV := reflect.ValueOf(obj)\r\n\tif !isStructPtr(objT) {\r\n\t\treturn template.HTML(\"\")\r\n\t}\r\n\tobjT = objT.Elem()\r\n\tobjV = objV.Elem()\r\n\r\n\tvar raw []string\r\n\tfor i := 0; i < objT.NumField(); i++ {\r\n\t\tfieldV := objV.Field(i)\r\n\t\tif !fieldV.CanSet() || unKind[fieldV.Kind()] {\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\tfieldT := objT.Field(i)\r\n\t\tlabel, name, fType, id, class, ignored, required, pattern, remote, optionqs, err := parseFormTag(fieldT)\r\n\t\tif ignored {\r\n\t\t\tcontinue\r\n\t\t}\r\n\r\n\t\traw = append(raw, renderFormField(label, name, fType, fieldV.Interface(), id, class, required, pattern, remote, optionqs, err))\r\n\r\n\t}\r\n\treturn template.HTML(strings.Join(raw, \"\"))\r\n}\r\n\r\n// renderFormField returns a string containing HTML of a single form field.\r\n// func renderFormField(label, name, fType string, value interface{}, id string, class string, required bool) string {\r\nfunc renderFormField(label, name, fType string, value interface{}, id string, class string, required bool, pattern string, remote string, optionqs string, err string) string {\r\n\tforId := \"\"\r\n\tif id != \"\" {\r\n\t\tforId = id\r\n\t\tid = \" id=\\\"\" + id + \"\\\"\"\r\n\t}\r\n\r\n\tif class == \"\" {\r\n\t\tclass = \"form-control\"\r\n\t} else {\r\n\t\tclass = class + \" form-control\"\r\n\t}\r\n\tclass = \" class=\\\"\" + class + \"\\\"\"\r\n\r\n\tif pattern != \"\" {\r\n\t\tpattern = \" pattern=\\\"\" + pattern + \"\\\"\"\r\n\t}\r\n\r\n\tif remote != \"\" {\r\n\t\tremote = \" data-remote=\\\"\" + remote + \"\\\"\"\r\n\t}\r\n\r\n\tif err != \"\" {\r\n\t\terr = \" data-error=\\\"\" + err + \"\\\"\"\r\n\t}\r\n\r\n\trequiredString := \"\"\r\n\tif required {\r\n\t\trequiredString = \" required\"\r\n\t}\r\n\r\n\tcommonTemplStart := \"<div class=\\\"form-group\\\">\"\r\n\tcommonTemplEnd := \"<div class=\\\"help-block with-errors\\\"></div></div>\"\r\n\tcommonInputTemplStart := \"<div class=\\\"form-group\\\"><div class=\\\"input-group\\\"><span class=\\\"input-group-addon\\\">\"\r\n\tcommonInputTemplEnd := \"</div><div class=\\\"help-block with-errors\\\"></div></div>\"\r\n\r\n\tif fType == \"hidden\" {\r\n\t\treturn fmt.Sprintf(`%v<input%v%v name=\"%v\" type=\"%v\" value=\"%v\"%v%v%v%v>%v`, commonTemplStart, id, class, name, fType, value, requiredString, pattern, remote, err, commonTemplEnd)\r\n\t}\r\n\r\n\tif fType == \"textarea\" {\r\n\t\treturn fmt.Sprintf(`%v<label for=\"%v\">%v</label><%v%v%v name=\"%v\"%v%v%v%v>%v</%v>%v`, commonTemplStart, forId, label, fType, id, class, name, requiredString, pattern, remote, err, value, fType, commonTemplEnd)\r\n\t}\r\n\r\n\tif fType == \"multiselect\" {\r\n\t\t// optionqs := interface{optionqs}\r\n\t\tfmt.Println(optionqs)\r\n\t\toptionTxt := \"\"\r\n\t\ts := reflect.ValueOf(value)\r\n\t\tif s.IsValid() {\r\n\t\t\tfor i := 0; i < s.Len(); i++ {\r\n\t\t\t\ta := s.Index(i)\r\n\t\t\t\tvar opVal string\r\n\t\t\t\tvar opName string\r\n\t\t\t\tfor k := 0; k < a.NumField(); k++ {\r\n\t\t\t\t\tif a.Type().Field(k).Name == \"Id\" {\r\n\t\t\t\t\t\topVal = fmt.Sprintf(\"%v\", a.Field(k))\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif a.Type().Field(k).Name == \"Name\" {\r\n\t\t\t\t\t\topName = fmt.Sprintf(\"%v\", a.Field(k))\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\toptionTxt = fmt.Sprintf(\"%v<option value=\\\"%v\\\" selected=selected>%v</option>\", optionTxt, opVal, opName)\r\n\t\t\t}\r\n\t\t\tvalue = optionTxt\r\n\t\t}\r\n\t\treturn fmt.Sprintf(`%v%v</span><select multiple=\"multiple\" %v%v name=\"%v\"%v%v%v%v>%v</select>%v`, commonInputTemplStart, label, id, class, name, requiredString, pattern, remote, err, value, commonInputTemplEnd)\r\n\t}\r\n\r\n\tif isValidForInput(fType) {\r\n\t\treturn fmt.Sprintf(`%v%v</span><input%v%v name=\"%v\" type=\"%v\" value=\"%v\"%v%v%v%v>%v`, commonInputTemplStart, label, id, class, name, fType, value, requiredString, pattern, remote, err, commonInputTemplEnd)\r\n\t}\r\n\r\n\treturn fmt.Sprintf(`%v%v</span><%v%v%v name=\"%v\"%v%v%v%v>%v</%v>%v`, commonInputTemplStart, label, fType, id, class, name, requiredString, pattern, remote, err, value, fType, commonInputTemplEnd)\r\n\r\n}\r\n\r\n// isValidForInput checks if fType is a valid value for the `type` property of an HTML input element.\r\nfunc isValidForInput(fType string) bool {\r\n\tvalidInputTypes := strings.Fields(\"text password checkbox radio submit reset hidden image file button search email url tel number range date month week time datetime datetime-local color\")\r\n\tfor _, validType := range validInputTypes {\r\n\t\tif fType == validType {\r\n\t\t\treturn true\r\n\t\t}\r\n\t}\r\n\treturn false\r\n}\r\n\r\n// parseFormTag takes the stuct-tag of a StructField and parses the `form` value.\r\n// returned are the form label, name-property, type and wether the field should be ignored.\r\n// func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id string, class string, ignored bool, required bool) {\r\nfunc parseFormTag(fieldT reflect.StructField) (label, name, fType string, id string, class string, ignored bool, required bool, pattern string, remote string, optionqs string, err string) {\r\n\ttags := strings.Split(fieldT.Tag.Get(\"form\"), \",\")\r\n\tlabel = fieldT.Name + \": \"\r\n\tname = fieldT.Name\r\n\tfType = \"text\"\r\n\tignored = false\r\n\tid = fieldT.Tag.Get(\"id\")\r\n\tclass = fieldT.Tag.Get(\"class\")\r\n\r\n\tpattern = fieldT.Tag.Get(\"pattern\")\r\n\tremote = fieldT.Tag.Get(\"remote\")\r\n\terr = fieldT.Tag.Get(\"err\")\r\n\toptionqs = fieldT.Tag.Get(\"optionqs\")\r\n\r\n\trequired = false\r\n\trequired_field := fieldT.Tag.Get(\"required\")\r\n\tif required_field != \"-\" && required_field != \"\" {\r\n\t\trequired, _ = strconv.ParseBool(required_field)\r\n\t}\r\n\r\n\tswitch len(tags) {\r\n\tcase 1:\r\n\t\tif tags[0] == \"-\" {\r\n\t\t\tignored = true\r\n\t\t}\r\n\t\tif len(tags[0]) > 0 {\r\n\t\t\tname = tags[0]\r\n\t\t}\r\n\tcase 2:\r\n\t\tif len(tags[0]) > 0 {\r\n\t\t\tname = tags[0]\r\n\t\t}\r\n\t\tif len(tags[1]) > 0 {\r\n\t\t\tfType = tags[1]\r\n\t\t}\r\n\tcase 3:\r\n\t\tif len(tags[0]) > 0 {\r\n\t\t\tname = tags[0]\r\n\t\t}\r\n\t\tif len(tags[1]) > 0 {\r\n\t\t\tfType = tags[1]\r\n\t\t}\r\n\t\tif len(tags[2]) > 0 {\r\n\t\t\tlabel = tags[2]\r\n\t\t}\r\n\t}\r\n\r\n\treturn\r\n}\r\n\r\nfunc isStructPtr(t reflect.Type) bool {\r\n\treturn t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct\r\n}\r\n\r\n// go1.2 added template funcs. begin\r\nvar (\r\n\terrBadComparisonType = errors.New(\"invalid type for comparison\")\r\n\terrBadComparison     = errors.New(\"incompatible types for comparison\")\r\n\terrNoComparison      = errors.New(\"missing argument for comparison\")\r\n)\r\n\r\ntype kind int\r\n\r\nconst (\r\n\tinvalidKind kind = iota\r\n\tboolKind\r\n\tcomplexKind\r\n\tintKind\r\n\tfloatKind\r\n\tstringKind\r\n\tuintKind\r\n)\r\n\r\nfunc basicKind(v reflect.Value) (kind, error) {\r\n\tswitch v.Kind() {\r\n\tcase reflect.Bool:\r\n\t\treturn boolKind, nil\r\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\r\n\t\treturn intKind, nil\r\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:\r\n\t\treturn uintKind, nil\r\n\tcase reflect.Float32, reflect.Float64:\r\n\t\treturn floatKind, nil\r\n\tcase reflect.Complex64, reflect.Complex128:\r\n\t\treturn complexKind, nil\r\n\tcase reflect.String:\r\n\t\treturn stringKind, nil\r\n\t}\r\n\treturn invalidKind, errBadComparisonType\r\n}\r\n\r\n// eq evaluates the comparison a == b || a == c || ...\r\nfunc eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {\r\n\tv1 := reflect.ValueOf(arg1)\r\n\tk1, err := basicKind(v1)\r\n\tif err != nil {\r\n\t\treturn false, err\r\n\t}\r\n\tif len(arg2) == 0 {\r\n\t\treturn false, errNoComparison\r\n\t}\r\n\tfor _, arg := range arg2 {\r\n\t\tv2 := reflect.ValueOf(arg)\r\n\t\tk2, err := basicKind(v2)\r\n\t\tif err != nil {\r\n\t\t\treturn false, err\r\n\t\t}\r\n\t\tif k1 != k2 {\r\n\t\t\treturn false, errBadComparison\r\n\t\t}\r\n\t\ttruth := false\r\n\t\tswitch k1 {\r\n\t\tcase boolKind:\r\n\t\t\ttruth = v1.Bool() == v2.Bool()\r\n\t\tcase complexKind:\r\n\t\t\ttruth = v1.Complex() == v2.Complex()\r\n\t\tcase floatKind:\r\n\t\t\ttruth = v1.Float() == v2.Float()\r\n\t\tcase intKind:\r\n\t\t\ttruth = v1.Int() == v2.Int()\r\n\t\tcase stringKind:\r\n\t\t\ttruth = v1.String() == v2.String()\r\n\t\tcase uintKind:\r\n\t\t\ttruth = v1.Uint() == v2.Uint()\r\n\t\tdefault:\r\n\t\t\tpanic(\"invalid kind\")\r\n\t\t}\r\n\t\tif truth {\r\n\t\t\treturn true, nil\r\n\t\t}\r\n\t}\r\n\treturn false, nil\r\n}\r\n\r\n// ne evaluates the comparison a != b.\r\nfunc ne(arg1, arg2 interface{}) (bool, error) {\r\n\t// != is the inverse of ==.\r\n\tequal, err := eq(arg1, arg2)\r\n\treturn !equal, err\r\n}\r\n\r\n// lt evaluates the comparison a < b.\r\nfunc lt(arg1, arg2 interface{}) (bool, error) {\r\n\tv1 := reflect.ValueOf(arg1)\r\n\tk1, err := basicKind(v1)\r\n\tif err != nil {\r\n\t\treturn false, err\r\n\t}\r\n\tv2 := reflect.ValueOf(arg2)\r\n\tk2, err := basicKind(v2)\r\n\tif err != nil {\r\n\t\treturn false, err\r\n\t}\r\n\tif k1 != k2 {\r\n\t\treturn false, errBadComparison\r\n\t}\r\n\ttruth := false\r\n\tswitch k1 {\r\n\tcase boolKind, complexKind:\r\n\t\treturn false, errBadComparisonType\r\n\tcase floatKind:\r\n\t\ttruth = v1.Float() < v2.Float()\r\n\tcase intKind:\r\n\t\ttruth = v1.Int() < v2.Int()\r\n\tcase stringKind:\r\n\t\ttruth = v1.String() < v2.String()\r\n\tcase uintKind:\r\n\t\ttruth = v1.Uint() < v2.Uint()\r\n\tdefault:\r\n\t\tpanic(\"invalid kind\")\r\n\t}\r\n\treturn truth, nil\r\n}\r\n\r\n// le evaluates the comparison <= b.\r\nfunc le(arg1, arg2 interface{}) (bool, error) {\r\n\t// <= is < or ==.\r\n\tlessThan, err := lt(arg1, arg2)\r\n\tif lessThan || err != nil {\r\n\t\treturn lessThan, err\r\n\t}\r\n\treturn eq(arg1, arg2)\r\n}\r\n\r\n// gt evaluates the comparison a > b.\r\nfunc gt(arg1, arg2 interface{}) (bool, error) {\r\n\t// > is the inverse of <=.\r\n\tlessOrEqual, err := le(arg1, arg2)\r\n\tif err != nil {\r\n\t\treturn false, err\r\n\t}\r\n\treturn !lessOrEqual, nil\r\n}\r\n\r\n// ge evaluates the comparison a >= b.\r\nfunc ge(arg1, arg2 interface{}) (bool, error) {\r\n\t// >= is the inverse of <.\r\n\tlessThan, err := lt(arg1, arg2)\r\n\tif err != nil {\r\n\t\treturn false, err\r\n\t}\r\n\treturn !lessThan, nil\r\n}\r\n\r\n// MapGet getting value from map by keys\r\n// usage:\r\n// Data[\"m\"] = map[string]interface{} {\r\n//     \"a\": 1,\r\n//     \"1\": map[string]float64{\r\n//         \"c\": 4,\r\n//     },\r\n// }\r\n//\r\n// {{ map_get m \"a\" }} // return 1\r\n// {{ map_get m 1 \"c\" }} // return 4\r\nfunc MapGet(arg1 interface{}, arg2 ...interface{}) (interface{}, error) {\r\n\targ1Type := reflect.TypeOf(arg1)\r\n\targ1Val := reflect.ValueOf(arg1)\r\n\r\n\tif arg1Type.Kind() == reflect.Map && len(arg2) > 0 {\r\n\t\t// check whether arg2[0] type equals to arg1 key type\r\n\t\t// if they are different, make conversion\r\n\t\targ2Val := reflect.ValueOf(arg2[0])\r\n\t\targ2Type := reflect.TypeOf(arg2[0])\r\n\t\tif arg2Type.Kind() != arg1Type.Key().Kind() {\r\n\t\t\t// convert arg2Value to string\r\n\t\t\tvar arg2ConvertedVal interface{}\r\n\t\t\targ2String := fmt.Sprintf(\"%v\", arg2[0])\r\n\r\n\t\t\t// convert string representation to any other type\r\n\t\t\tswitch arg1Type.Key().Kind() {\r\n\t\t\tcase reflect.Bool:\r\n\t\t\t\targ2ConvertedVal, _ = strconv.ParseBool(arg2String)\r\n\t\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\r\n\t\t\t\targ2ConvertedVal, _ = strconv.ParseInt(arg2String, 0, 64)\r\n\t\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:\r\n\t\t\t\targ2ConvertedVal, _ = strconv.ParseUint(arg2String, 0, 64)\r\n\t\t\tcase reflect.Float32, reflect.Float64:\r\n\t\t\t\targ2ConvertedVal, _ = strconv.ParseFloat(arg2String, 64)\r\n\t\t\tcase reflect.String:\r\n\t\t\t\targ2ConvertedVal = arg2String\r\n\t\t\tdefault:\r\n\t\t\t\targ2ConvertedVal = arg2Val.Interface()\r\n\t\t\t}\r\n\t\t\targ2Val = reflect.ValueOf(arg2ConvertedVal)\r\n\t\t}\r\n\r\n\t\tstoredVal := arg1Val.MapIndex(arg2Val)\r\n\r\n\t\tif storedVal.IsValid() {\r\n\t\t\tvar result interface{}\r\n\r\n\t\t\tswitch arg1Type.Elem().Kind() {\r\n\t\t\tcase reflect.Bool:\r\n\t\t\t\tresult = storedVal.Bool()\r\n\t\t\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\r\n\t\t\t\tresult = storedVal.Int()\r\n\t\t\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:\r\n\t\t\t\tresult = storedVal.Uint()\r\n\t\t\tcase reflect.Float32, reflect.Float64:\r\n\t\t\t\tresult = storedVal.Float()\r\n\t\t\tcase reflect.String:\r\n\t\t\t\tresult = storedVal.String()\r\n\t\t\tdefault:\r\n\t\t\t\tresult = storedVal.Interface()\r\n\t\t\t}\r\n\r\n\t\t\t// if there is more keys, handle this recursively\r\n\t\t\tif len(arg2) > 1 {\r\n\t\t\t\treturn MapGet(result, arg2[1:]...)\r\n\t\t\t}\r\n\t\t\treturn result, nil\r\n\t\t}\r\n\t\treturn nil, nil\r\n\r\n\t}\r\n\treturn nil, nil\r\n}\r\n```\r\n\r\n4. What did you expect to see?\r\n\r\nexec models.GetCategoryOptions to get options rendered\r\n5. What did you see instead?"}}
{"actor":{"display_login":"xurwxj"}}