How to pass multiple values from template to template? - loops

My City struct is like this:
type City struct {
ID int
Name string
Regions []Region
}
And Region struct is:
type Region struct {
ID int
Name string
Shops []Destination
Masters []Master
EducationCenters []Destination
}
In main I try to do this:
tpl.ExecuteTemplate(resWriter,"cities.gohtml",CityWithSomeData)
Is it possible to do something like this inside template?
{{range .}}
{{$city:=.Name}}
{{range .Regions}}
{{$region:=.Name}}
{{template "data" .Shops $city $region}}
{{end}}
{{end}}

Quoting from the doc of text/template, the syntax of the {{template}} action:
{{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.
This means you may pass one optional data to the template execution, not more. If you want to pass multiple values, you have to wrap them into some single value you pass. For details, see How to pass multiple data to Go template?
So we should wrap those data into a struct or a map. But we can't write Go code in a template. What we may do is register a function to which we pass these data, and the function may do the "packing" and return a single value which now we can pass to the {{template}} action.
Here's an example wrapper which simply packs these into a map:
func Wrap(shops []Destination, cityName, regionName string) map[string]interface{} {
return map[string]interface{}{
"Shops": shops,
"CityName": cityName,
"RegionName": regionName,
}
}
Custom functions can be registered using the Template.Funcs() method, and don't forget you have to do this before you parse the template text.
Here's a modified template which calls this Wrap() function to produce a single value:
const src = `
{{define "data"}}
City: {{.CityName}}, Region: {{.RegionName}}, Shops: {{.Shops}}
{{end}}
{{- range . -}}
{{$city:=.Name}}
{{- range .Regions -}}
{{$region:=.Name}}
{{- template "data" (Wrap .Shops $city $region) -}}
{{end}}
{{- end}}`
And here's a runnable example showing these in action:
t := template.Must(template.New("cities.gohtml").Funcs(template.FuncMap{
"Wrap": Wrap,
}).Parse(src))
CityWithSomeData := []City{
{
Name: "CityA",
Regions: []Region{
{Name: "CA-RA", Shops: []Destination{{"CA-RA-SA"}, {"CA-RA-SB"}}},
{Name: "CA-RB", Shops: []Destination{{"CA-RB-SA"}, {"CA-RB-SB"}}},
},
},
{
Name: "CityB",
Regions: []Region{
{Name: "CB-RA", Shops: []Destination{{"CB-RA-SA"}, {"CB-RA-SB"}}},
{Name: "CB-RB", Shops: []Destination{{"CB-RB-SA"}, {"CB-RB-SB"}}},
},
},
}
if err := t.ExecuteTemplate(os.Stdout, "cities.gohtml", CityWithSomeData); err != nil {
panic(err)
}
Output (try it on the Go Playground):
City: CityA, Region: CA-RA, Shops: [{CA-RA-SA} {CA-RA-SB}]
City: CityA, Region: CA-RB, Shops: [{CA-RB-SA} {CA-RB-SB}]
City: CityB, Region: CB-RA, Shops: [{CB-RA-SA} {CB-RA-SB}]
City: CityB, Region: CB-RB, Shops: [{CB-RB-SA} {CB-RB-SB}]

I guess CityWithSomeData is a slice, if so have a try like that:
type viewModel struct {
List []City
}
then, in your template:
{{range .List}}
{{$city:=.Name}}
{{range .Regions}}
{{$region:=.Name}}
{{template "data" .Shops $city $region}}
{{end}}
{{end}}

You need the generic dict function that allows to build a map[string]interface{} from a list of parameters.
See https://stackoverflow.com/a/18276968/328115

Related

Angular Use Function in Container Context

I want to set up a checkbox structure and I want to handle it dynamically. I have an object response returned from my service. However, when I use this function in context, I get a string return and I cannot use ngFor.
form.demo.component.ts
getElementChoicesByNKey(nkey:string):choiceModel[]{
var element = this.findInComponentsByNKey(nkey);
var res = element.Choices;
return res;
}
this function gives the correct return.
form.demo.component.html
...
<ng-container *ngIf="item.Type == 'Choice'">
<ng-container *ngTemplateOutlet="choiceTheme; context:{ Id: item.Id, Label: item.Label, Choices: getElementChoicesByNKey(item.Id) }"></ng-container>
</ng-container>
...
<ng-template #choiceTheme let-Id="Id" let-Label="Label" let-Choices="Choices">
<nz-form-item>
<nz-form-label nzFor="Id">{{Label}}</nz-form-label>
<nz-form-control [formControlName]="Id" nzErrorTip="{{ 'form.requiredText' | translate }}">
<p>{{Choices.length}}</p>
<div *ngFor="let item of Choices">
<p>test</p>
</div>
</nz-form-control>
</nz-form-item>
</ng-template>
...
here Choices appears as string and won't let me use ngFor. I am getting an error as below.
Cannot find a differ supporting object '[
{ label: 'Apple', value: 'Apple', checked: true },
{ label: 'Pear', value: 'Pear', checked: false },
{ label: 'Orange', value: 'Orange', checked: false } ]' of type 'string'. NgFor only supports binding to Iterables such as Arrays.
What is the point I missed? Thank you for your help.
Use
*ngFor="let item of getChoices(Choices)" in template
and in component.ts
getChoices(choiceStr) {
return JSON.parse(choiceStr);
}
Since you are getting Choices as a string, parse the string to an array inorder for ngFor to work

Mongoose Schema. How to create default value for a object of object?

Meet my UserModel:
var UserModel = mongoose.model('UserModel',
{
username: { type: String, default: 'Nameless'},
password: String,
registry: String,
});
I want to do something like this to my username key:
username: {
description: {type: String, default: 'Name'},
value: {type: String, default: 'Nameless'}
};
My goal is to use this keys in a ng-repeat, so I can do something like this:
<p> {{ user.username.desc }}: {{ user.username.value }} </p>
With output: Name: Nameless
My problem is: I should be doing something wrong. I'm receiving syntax errors and my server dont even start.
:)
You can set default with a function, so create one, also you can use preSave to validate your model like:
UserModel.pre('save', function(next) {
var self = this;
// validate username field here
});
}
more info here http://mongoosejs.com/docs/middleware.html

Angular filter by array that contains search criteria

Does the built in Angular "filter" support filtering an array in the sense that "filter where array contains "
Such as follows:
$scope.currentFilter = "Allentown";
$scope.users = [{
name: "user1",
locations: [
{ name: "New York", ... },
{ name: "Allentown", ... },
{ name: "Anderson", ... },
]
}, ... ];
<div ng-repeat="user in users | filter : { locations: { name: currentFilter } }"></div>
In other words I'm looking to filter to only users with a "locations" array that CONTAINS a location that matches the string by name.
If not, how can I accomplish this with a custom filter?
Your code snippet works as is since Angular 1.2.13. In case you're using an older version (tested on 1.0.1) and don't need to reuse your filtering routine across controllers (in which case you should declare a proper filter), you can pass the built-in filter a predicate function :
<div ng-repeat="user in users | filter : hasLocation">{{user.name}}</div>
And write something like this :
$scope.currentFilter = "Allentown";
$scope.hasLocation = function(value, index, array) {
return value.locations.some(function(location) {
return location.name == $scope.currentFilter;
});
}
Fiddle here.

meteor autoform string array shows empty field

I make edit form for some collection, it has Array fields 'phones', each element is String
When I trying to make afArrayField from this field it shows block with one empty string
Schema:
{phones:
{type: Array,
minCount: 1,
label: "Phones numbers"},
{"phones.$":
{type: String}
}
Template:
{{> afQuickField name="phones" value=phones}}
In object array 'phones' is presented
I've the following:
phones: {
type: [String],
minCount: 1,
label: "Phones numbers"
},
'phones.$': {
autoform: {
afFieldInput: {
type: 'text'
}
}
}
Template helper
Template.home.helpers({
doc: {phones: ['09988765', '0998776']} // this should come from db.findOne
})
In template:
{{#autoForm id='test' schema="Schema.Array" type="update" doc=doc}}
{{> afQuickField name="phones" value=doc.phones}}
{{/autoForm}}
I'm having this:
I've the following package dependencies:
meteor-platform
standard-app-packages
iron:router
iron:layout
aldeed:collection2
aldeed:simple-schema
aldeed:autoform
nemo64:bootstrap
less
accounts-base
accounts-password

Initialize an array of structs inside a nested struct in golang

I am wondering how can I define and initialize and array of structs inside a nested struct, for example:
type State struct {
id string `json:"id" bson:"id"`
Cities
}
type City struct {
id string `json:"id" bson:"id"`
}
type Cities struct {
cities []City
}
Now how can I Initialize such a structure and if someone has a different idea about how to create the structure itself.
Thanks
In your case the shorthand literal syntax would be:
state := State {
id: "CA",
Cities: Cities{
[]City {
{"SF"},
},
},
}
Or shorter if you don't want the key:value syntax for literals:
state := State {
"CA", Cities{
[]City {
{"SF"},
},
},
}
BTW if Cities doesn't contain anything other than the []City, just use a slice of City. This will lead to a somewhat shorter syntax, and remove an unnecessary (possibly) layer:
type State struct {
id string `json:"id" bson:"id"`
Cities []City
}
type City struct {
id string `json:"id" bson:"id"`
}
func main(){
state := State {
id: "CA",
Cities: []City{
{"SF"},
},
}
fmt.Println(state)
}
Full example with everything written out explicitly:
state := State{
id: "Independent Republic of Stackoverflow",
Cities: Cities{
cities: []City{
City{
id: "Postington O.P.",
},
},
},
}

Resources