Reuse a partial with different content, in the same view - javascript

As described in the Sails.js documentation:
All of your locals will be sent to the partial automatically.
So I was wondering how I can use the same partial multiple times, in the same view, but with different content.
Let's say I have a list of the top 3 users, and a list of the newest 3 users.
The lists have the same HTML structure, and same CSS styling but their content is different.
How can I use the same partial (user/list.ejs for example) to display both the lists?
Does anyone know if there's a way to pass specific data to the partial, instead of the view locals?
Thanks in advance.
Dennis

Sails uses the ejs-locals library to handle partials, which allows sending options to the partial as the second argument. So in your template you can do:
<h1>Top users: </h1>
<p>
<%= partial('user/list.ejs', {users: topUsers}) %>
</p>
<h1>New users: </h1>
<p>
<%= partial('user/list.ejs', {users: newUsers}) %>
</p>
to supply different values for users inside in the user/list.ejs partial, provided that you supply topUsers and newUsers as locals when you display the view that's including the partial, i.e. in your controller action:
res.view("myView", {topUsers: [array of users], newUsers: [array of users]});

Related

Best practice for displaying Firebase many-to-many relationships in the view (AngularFire)

I have found a lot of examples on how to structure many-to-many relationships in Firebase. Following the most recommended way I've seen to set it up I have some basic posts and tags data in Firebase:
/posts:
-K_GOdSQvCQ2sAcHfo1x
- descpripton: "This is a post..."
- title: "This is a title..."
- tags:
-K_aBTTDKVUovZe3l0lX: true
.....
-K_GFDQjPoSmCJM3YAlB:
- description: "Another post..."
- title: "This title..."
- tags:
-K_aBTTKDhYsnbFv1Tuc: true
......
/tags:
-K_aBTTDKVUovZe3l0lX
- name: "Sport"
- postIds:
-K_GOdSQvCQ2sAcHfo1x: true
.....
-K_aBTTKDhYsnbFv1Tuc:
- name: "Movies"
- postIds:
-K_GFDQjPoSmCJM3YAlB: true
.....
My problem is figuring out how to handle these relationships in my views. I haven't been able to find any tutorials or examples covering it.For example, in the index view I wish to list all posts with their respective tags attached.
So far I've been simply returning all posts and all tags and storing them in separate $scope variables. That's fine but I haven't been able to figure out how to display only the tags relative to each post. I first thought it should be possible trying a nested ng-repeat structure. But it's proving trickier than I expected to get this working.
This is the idea of what I am trying to achieve.
<!-- For each tag in post object iterate tags -->
<div data-ng-repeat="t in posts.tags">
<span data-ng-repeat="tag in tags">
<!-- display only tags here that match with post.tag.id -->
</span>
</div>
I'm thinking that it is perhaps possible using Angular's filter in conjunction with ng-repeat but I've had no luck finding any examples to work from. Maybe what I am trying to do is not possible in the view alone or too cumbersome/ugly. If anyone can give me some pointers on how I might approach it that would be great!
UPDATE
Ok, I have found a way to achieve this but I'm sure it's not optimal. If anyone can inform me on a better approach I'd be grateful.
For example, in the code below I feel that using <h5 ng-if="key === post.$id"> isn't the right way to match the posts to the tags. Maybe there is a standard way of using the boolean values to do this? I'm still a bit new to Firebase/AngularFire so I am eager to learn any emerging design patterns for solving this problem.
Again, the goal is pretty standard. The posts and tags are coming from separate Firebase nodes that have a many-to-many relationship(allowing posts to have many tags and tags to belong to many posts).
In the controller for the index view all posts and all tags are retrieved and saved separately to their own $scope variables. The following view code is how I managed to display the relevant tags inside each post preview.
<li data-ng-repeat="post in posts">
........
<div ng-repeat="tag in tags"> // Iterate tags
<div ng-repeat="(key, value) in tag.postIds"> // Iterate postIds in each tag
// Check tag.postId key against the current post id.
// Should be using booleans some way here instead??
<h5 ng-if="key === post.$id">
<span class="label label-default">
{{tag.name}}
</span>
</h5>
</div>
</div>
</li>
Short answer: denormalize your data.
A bit longer answer: You need to save the data in a way that helps you be efficient when you query it. So for this particular case, you could save the tag's name instead of just true which only shows association.
So instead of
{
posts:
-K_GOdSQvCQ2sAcHfo1x: {
descpripton: "This is a post...",
title: "This is a title...",
tags: {
-K_aBTTDKVUovZe3l0lX: true
}
}
}
You could save it like
{
posts:
-K_GOdSQvCQ2sAcHfo1x: {
descpripton: "This is a post...",
title: "This is a title...",
tags: {
-K_aBTTDKVUovZe3l0lX: "Sport" // <----- Notice the change
}
}
}
Watch this (and others, like this playlist) videos from the official Firebase chanel. Extremely helpful.

Using FluentValidation on a collection that creates partial views not displaying error messages

We are currently using FluentValidation in our MVC project. We needed to be able to create a dynamic view where users could add or remove items. This is accomplished using partialviews.
<div id="LocationsContainer">
#foreach (var location in Model.Locations)
{
Html.RenderPartial("_Location", location);
}
#Html.ValidationMessageFor(m => m.Locations)
<br />
</div>
And within the partial view I just have a few fields.
...
<div class="float-box">
<div class="label">
#Html.LabelFor(m => m.PropertyAddress)
</div>
#Html.TextBoxFor(m => m.PropertyAddress)
<br />
#Html.ValidationMessageFor(m => m.PropertyAddress)
</div>
<div class="float-box">
<div class="label">
#Html.LabelFor(m => m.ApartmentNo)
</div>
#Html.TextBoxFor(m => m.ApartmentNo)
<br />
#Html.ValidationMessageFor(m => m.ApartmentNo)
</div>
...
In my validator i set the validator for Model.Locations (which creates the partial views) by calling SetCollectionValidator
RuleFor(vm => vm.Locations).SetCollectionValidator(new ServiceAddressViewModelValidator());
In my controller where I call ModelState.IsValid it seems to be working/validating. I can see that errors are caught inside my partial view according to my validation rules. I just can't get the error messages to display. In my validation result i can see error messages but there not getting applied to the UI. Am i doing something wrong here? I even tried using dataannotations with fluentvalidation for things other than the partial views and I got weird behavior. Doing this approach it appeared when fluentvalidation displayed error messages then the data annotation error messages didn't display and when the data annotation error messages displayed it only worked for the first partial view. If i had more than one it wasn't getting applied to the other views. Any ideas how i can get this to work? (With fluentvalidation or data annotations)?
Properties on a class are only validated if the class is instantiated. If no data for the class is posted at all, the modelbinder will not instantiate it. Your problem here, is that while you may be posting data, your form fields are not named properly, so the the modelbinder doesn't know what to do with them and discards the information. As a result, your collection items are never instantiated and validation is never run. To fix your issue, you need to use for rather than foreach:
#for (var i = 0; i < Model.Locations.Count(); i++)
{
Html.RenderPartial("_Location", Model.Locations[i]);
}
Or, since all you're doing is rendering a partial, you can actually take a short cut if you use editor templates. First create the view Views\Shared\EditorTemplates\Location.cshtml. In that view, put the contents of your current partial view that your using for locations. Then, all you need in your main view is:
#Html.EditorFor(m => m.Locations)
Razor will see you have an editor template for a Location class (The template name should match the class name. If it's not Location, rename the template to match.) and since you have a collection, it will render that template for each item in the collection.

How to use a template with textboxes loaded with data passed from a calling template in ember.js

I'm trying to make a addstudent template which can be rendered with data if clicked on editstudent option from another template.
I don't want to make different templates for addStudentDetails and EditstudentDetails. how to create a single template for this both functions.
can anyone help me with this?
I see a couple ways of doing this.
Handlebar template, using conditionals.
Then in your controller you can control whether you want to edit or add.
The ember guide has a good example of this for controlling state.
Or you can use Routes and Resources. Possibly a Parent Resource called Student and then routes called edit and add. But you said you didn't want to use different templates so I'm assuming you'll probably want to use #1.
//inside your controller
App.StudentController = Ember.ObjectController.extend({
editStudent: true // or false
});
<!-- handlebars template possibly called studentTemplate -->
{{#if editStudent}}
<!-- code for editStudent -->
{{else}}
<!-- code for addStudent -->
{{/if}}
Hope that answers your question.

Knockout SPA: Different Layouts(Master pages)

I'm building SPA application with knockout.js .
Basically what i do is bind as current page a ko component depending on what is route.
It looks something like
<div id="currentPage" data-bind="component: { name: currentRoute.page,
attr: currentRoute }>
</div>
This is for the current page and the whole picture whit the layout looks like:
<html>
<head></head>
<body>
<div data-bind="component: {name: "nav"}></div>
<div data-bind="component: {name: "aside"}></div>
<div id="currentPage" data-bind="component: { name: currentRoute.page,
attr: currentRoute}">
</div>
</body
</html>
The problem is that i dont have one layout.. the other one looks like this (pseudo used)
<html>
<body>
<wrapper>
<currentPage>
</wrapper>
</body
</html>
So basically the first layout is not direct parent of the currentPage module but the second is..
The variants for dynamic layout changing that i can think of are
Specify the layout components in each page.. But i dont think it is good idea cause i will be writing the same code over and over and will not be able to persist the state in the layout component because of when i change the next page the layout will be recreated( not fully but enough to loose the state )
The layout is separate from the currentPage component so only the currentComponent binding will be changed.. this is perfect for persisting state in layout but not good when i have variant where i want different layout for example which is wrapper around the componentBinding..
I'll be very happy if some one shares fresh ideas how to solve such problems.
In knockout if any part of view is to be dynamically changed you got to have bindings attached to the view. You say that the outer layout of the page is dependent on the inner page being displayed, so logically I consider it part of that page view definition. That is why I would not look for some special way to handle this case.
If I am not missing something, the reasonable thing to do in this case is to just include layout in each page. You could then handle repetitive code by using "traditional" approach using knockout templates (especially Note 5 on dynamic templates from http://knockoutjs.com/documentation/template-binding.html) and code extraction.
Completely other approach you might want to take is to put all layouts in master page and then control them by using bindings like "if" and "visible".

Dynamically render partial templates using mustache

Is there a way to dynamically inject partial templates (and have it work the same way in both Ruby & Javascript)? Basically, I'm trying to render different types of objects in a list.
The best I can come up with is this:
<div class="items">
{{#items}}
<div class="item">
{{#is_message}}
{{> message}}
{{/is_message}}
{{#is_picture}}
{{> picture}}
{{/is_picture}}
</div>
{{/items}}
</div>
I'm not super-psyched about this approach.
Is there a better way?
Also note that the different types of models for the views can have non-similar fields. I suppose I could always go to the lowest common denominator and have the data hash contain the html, however I would rather use the mustache templates.
I did the same thing you did, and for each property type i needed a dynamic partial, I just set a dynamic variable in the js data model that's being rendered in the template...
eval("this.set({is_" + this.get("propertyType") + ": true})")
or
this["is_" + propertyType] = true
At least I don't have to manually set the 'is_whatever' variable...
It would be cool if mustache.js or ICanHaz.js had some clever syntax for dynamic properties inside of mustache tags... maybe something like this:
{{>{{message}} }}

Categories