I've created two custom action->object pairs in my app with identical structure (except each one has a own one custom property).
1) action: 'Rescue' -> object: 'Guardian'
Guardian have custom property 'stage' (string type)
2) action: 'Complete' -> object: 'Level'
Level have custom property 'level_type' (string type)
3) art (images) - both have 200x200 px
But they displays in different layout when i post them, and acts differently.
1) Complete a level story sample:
The description for level not displayed, and not shown on level title hover. The image looks small then for guardian (but they both same size)
2) Rescue a Guardian sample. It looks like it should.
I want 'Complete a level' story looks same as 'Rescue a Guardian'
Please advance, thanks!
Related
I want to document once and for all for myself (and keep a permanent record!) of the relationship between parents and children and the ideal json structure, along with basic examples of routes and controllers.
As I (hopefully) get answers and comments I will update the question to reflect best practice.
So, I have my ember models :
App.Customer = DS.Model.extend({
name: DS.attr('string' ),
orders: DS.hasMany("order")
});
App.Order = DS.Model.extend({
carrier: DS.attr('string' ),
customer: DS.belongsTo("customer")
orderlines: DS.hasMany("orderline")
});
App.Orderline = DS.Model.extend({
order: DS.belongsTo("order"),
item: DS.belongsTo("item"),
price: DS.attr('number'),
qty: DS.attr('number'),
});
App.Item = DS.Model.extend({
name: DS.attr('string'),
orderlines: DS.hasMany("orderline")
});
Question 1: are these model definitions correct ?
There are several approaches that I could take to viewing this data:
Customer Tab | Orders Tab | Order lines tab
Customer page -> Orders Page -> Order lines page
Treeview
Can anyone suggest any other JS widgets that could display this hierarchical data ?
Question 2:
what are the router / controllers that are required for each of these ?
I have option 2) working as far as displaying the customer, but when I click on the orders link for the customer I am getting all orders. It could be that my json is wrong .. or more likely I don't know how to display all the orders of the selected customer. Or both :(
I currently have :
{"customers":[
{"name":"foobar inc","id":"0x181","orders":["0x386","0x3a4"]},
{"name":"barfoo ltd","id":"0x182","orders":["0x3de","0x3fd"]} ],
"orders":[
{"carrier":"Standard Mail","id":"0x386","customer_id":"0x181"},
{"carrier":"FlyByNight Courier","id":"0x3a4","customer_id":"0x181"},
{"carrier":"Standard Mail","id":"0x3de","customer_id":"0x182"},
{"carrier":"FlyByNight Courier","id":"0x3fd","customer_id":"0x182"} ]}
Question 3: is this correct ? (I can make the json come out in any format, so it's probably best to create the json structure that best suits ember-data).
Question 4: should I be including related data at this point (so all customers, all orders, all orderlines)? Or would it be better not to include the child data, but get these on demand from the server ?
I'll leave it for now - hopefully I can start to make sense of the nested data soon ! thanks.
Question 1 Those model definitions look good to me.
Question 2 You may want to end up with a mixture of your options #1 and #2. Tabs to let you see the entire list of each model, but with the ability to drill down hierarchically, on the /customers page, for instance. The exact routes that you need depend on the exact URLs that you want to have available in your app which will correspond to the screens/views that you want to show.
Let's say that you wanted these URLs/screens
/customers - The list of all customers
/customers/1 - The details about customer #1
/customers/1/orders - All orders for customer #1
/customers/1/orders/1 - The details for order #1 (including OrderLines)
Then your routes would be:
App.Router.map(function() {
this.resource('customers');
this.resource('customer', { path: '/customers/:customer_id' }, function(){
this.resource('orders');
this.resource('order', { path: '/orders/:order_id'});
});
});
Question 3 Yes, that JSON looks correct.
Question 4 That depends on the needs of your app. Probably you don't want to include the entire tree of data in a single request (Customers -> Orders -> OrderLines -> Items). You probably want to progressively load things as the user goes down a tree.
For instance you'd want to load just list list of customers at first, and then when the user clicks on a customer, you'd want to fire a request to get all of the orders for that customer. And so on, down the tree.
Here's a JSBin showing the general idea : http://jsbin.com/ucanam/1074/edit
Note that the hasMany relationships are defined with {async:true}. This allows them to be looked up on demand, instead of loaded with the parent model.
If you switched to the RESTAdapter, when it tries to load the list of orders for a customer it would make a request like :
/orders?ids[]=0x3de&ids[]=0x3fd
[UPDATE] : In response to the comments.
So, for the url structure that you requested : > >List of customers > -> customer details > -> list of orders > -> order details > -> list of order lines > -> order line details
You are very close with your JSBin. The thing that's tripping you up is the way that nesting of templates works.
The 'order' template, if it exists, is rendered for any and all routes that match /orders/xxx or /orders/xxx/*. If there are other parts of the route like /orderlines those templates get rendered into the 'order' template. But, since your 'order' template doesn't have an {{outlet}} there is nothing for the 'orderlines' template to render into.
Here's a slightly modified JSBin : http://jsbin.com/iKIsisO/3/edit
The only change there is the addition of the {{outlet}} to the bottom of the 'order' template.
Now, rendering orderlines below, or otherwise inside of the main order detail may not be what you want. Most likely you want the orderlines to replace the other order info. In this case you can rename the 'order' template to be 'order/index'. (You can also remove the OrderRoute and the needs from the OrderController).
Another JSBin, with the template renamed : http://jsbin.com/iDiMOCO/1/edit
So, what's happening here?
Using the Order model as an example, when you visit the /orders route, and any other routes that apply to the collection (/orders/new, /orders/some_custom_batch_thing), the main 'orders' template is rendered if it exists, then the sub path templates are rendered into 'orders'. If the 'orders' template does not exist, then the sub-path templates render into the {{outlet}} that is immediately up the chain. The /orders route is kind of a special case in that the sub-template for it is implicitly assumed to be orders/index. Similarly, with /orders/xxx and any other routes that apply to a single Order, the 'order' template is rendered first (if it exists), then the sub-path templates are rendered, either into 'order', or into the most immediate parent {{outlet}}. Also with /orders/xxx the 'order/index' template is the implicit sub-path template.
/orders :: 'orders' -> 'orders/index'
/orders/new :: 'orders' -> 'orders/new'
/order/xxx :: 'order' -> 'order/index'
/orders/xxx/edit :: 'order' -> 'order/edit'
So, the 'orders' and 'order' templates are really kind of like per-model-layout templates that can be used to decorate the sub-paths in a consistent way.
Final JSBin with template names rendered in the template and a few extra templates added to act as "model layouts": http://jsbin.com/iKIsisO/2/edit
I hope that all makes sense.
In TYPO3 6.x, what is an easy way to quickly create custom content elements?
A typical example (Maybe for a collection of testimonials):
In the backend (with adequate labels):
An image
An input field
A textarea
When rendering:
Image resized to xy
input wrapped in h2
textarea passed through parseFunc and wrapped in more markup
Ideally, these would be available in the page module as cType, but at least in the list module.
And use fluid templates.
My questions:
From another CMS I am used to content item templates being applied to the BE and the FE at the same time (you write the template for what it should do, and then there's a backend item just for that type of content element) - but that's not how fluid works - or can it be done?
Is there an extension that would handle such custom content elements (other than Templavoila)?
Or do I have to create a custom extbase/fluid extension for each such field type?
And, by the way: is there a recommendable tutorial for the new extbase kickstarter? I got scared away by all that domain modelling stuff.
That scaring domain modeling stuff is probably best option for you :)
Create an extension with FE plugin which holds and displays data as you want, so you can place it as a "Insert plugin". It's possible to add this plugin as a custom CType and I will find a sample for you, but little bit later.
Note, you don't need to create additional models as you can store required data ie. in FlexForm.
From FE plugin to CType
Let's consider that you have an extension with key hello which contains News controller with list and single actions in it.
In your ext_tables.php you have registered a FE plugin:
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin($_EXTKEY, 'News', 'Scared Hello News');
When it's working fine you can add it to the list of content types (available in TCA) just by adding fifth param to the configurePlugin method in your ext_localconf.php:
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'TYPO3.' . $_EXTKEY,
'News',
array('News' => 'list, show'),
array('News' => ''),
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT // <- this one
);
Next part (basing on this site) is adding your plugin to the New Content Element Wizard as noticed in TYPO3 Wiki since TYPO3 ver. 6.0.0 changed a little, so easiest way is adding something like this into your ext_tables.php:
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig('<INCLUDE_TYPOSCRIPT: source="FILE:EXT:hello/Configuration/TypoScript/pageTsConfig.ts">');
and in /typo3conf/ext/hello/Configuration/TypoScript/pageTsConfig.ts file write add this:
mod.wizards.newContentElement.wizardItems.plugins.elements.tx_hello_news {
icon = gfx/c_wiz/regular_text.gif
title = Scared Hello News
description = Displays Scared News
tt_content_defValues.CType = hello_news
}
# Below the same for TemplaVoila
templavoila.wizards.newContentElement.wizardItems.plugins.elements.tx_hello_news {
icon = gfx/c_wiz/regular_text.gif
title = Scared Hello News
description = Displays Scared News
tt_content_defValues.CType = hello_news
}
Note that proper key tx_hello_news should be combination of lowercased tx_, $_EXTKEY and plugin name - used in registerPlugin method.
You can stop here if you are bored ;)
Bring tt_content's fields back into your CType
Above steps will cause that no typical fields will be available in the TCA for your element, so you need to copy something or create own. To see how it works just see some sample, in the backend in left menu choose ADMIN TOOLS > Configuration > TCA > tt_content > types
There you'll find all types in the system, choose the most required and copy its [showitem] node into your own. Again in ext_tables.php add this PHP array:
$TCA['tt_content']['types']['hello_news']['showitem'] = $TCA['tt_content']['types']['textpic']['showitem'];
Again: hello_news is combination of lowercased $_EXTKEY and FE plugin name...
Of course if it's required you can compose quite own set of fields, one by one by custom string:
$TCA['tt_content']['types']['hello_news']['showitem'] = '--palette--;LLL:EXT:cms/locallang_ttc.xml:palette.general;general, --palette--;LLL:EXT:cms/locallang_ttc.xml:palette.header;header';
Access the fields in Extbase Controller:
Fortunately is easiest part as you can just access it as an Array:
$currentTtContent = $this->configurationManager->getContentObject()->data;
$header = $currentTtContent['header'];
debug($currentTtContent);
debug($header);
I think http://typo3.org/extensions/repository/view/dce will do exactly what I was looking for
I'm exploring the possibility of using MVC for my next e-commerce site. One thing I can't seem to figure out is whether or not I can use the same URL convention I normally use. Currently, the URL for any product could be one of the following:
Category/SubCategory/Product1.html
Category/SubCategory/SubSubCategory/Product2.html
Category/SubCategory/SubSubCategory/Product3.html
Category/SubCategory/SubSubCategory/SubSubSubCategory/Product4.html
etc.
The issue I'm having is with the nested category structure. So far the only thing I've come up with is as follows:
routes.MapRoute(
"Products",
"{categories}/{productname}",
new { controller = "Product", action = "Details", productname = UrlParameter.Optional },
new { categories = #"\w+/\w+" }
);
I was hoping that {categories} could be matched with any one of the following which I could process to identify the right category that the product belongs to:
Sport/Tennis/Rackets/ProductA
Sport/Badminton/Rackets/ProductB
But the route shown above doesn't work correctly.
Does anyone know how this can be achieved, or if it can't be done?
The routing system allows you to define catchall parameters, which ignore slashes and capture
everything up to the end of a URL. Designate a parameter as being catchall by prefixing it with an
asterisk (*).
routes.MapRoute(null, "Articles/{*articlePath}",
new { controller = "Articles", action = "Show" }
);
You can only have one catchall parameter in a URL pattern, and it must be the last (i.e.,
rightmost) thing in the URL, since it captures the entire URL path from that point onward.
One Caveat though, it doesn’t capture anything from the query string as route objects only look at the
path portion of a URL.
Catchall parameters are useful if you’re letting visitors navigate through some kind of arbitrary
depth hierarchy, such as in a content management system (CMS).
You can use the RouteData object to extract information about the route. For your needs, you would probably create a custom route handler that parses the route data and calls the correct controller methods.
You need access to the individual segments of the URL so you need to divide the category segment into two segments. That would make it much easier.
Let's say we call Tennis and Badminton categories and Rackets within those categories as a product class
You need a way to access the category, productClass and productName parameters. Supposing that "Sport" is fixed in this case, I will do it like this:
routes.MapRoute(
"Products",
"sport/{category}/{productClass}/{productName}",
new { controller = "Product", action = "Details", productClass = UrlParameter.Optional, productName = UrlParameter.Optional }
);
Your action method will be something like this
public ActionResult Details(string category, string productClass, string productName){
//Do whatever you need to do in order to get the specified product
}
You could use Areas in MVC2
So it would read:
Area/Controller/View/id
So in your case it would end up being:
Sport being the area,
Tennis The controller,
Rackets the view,
ProductA being an ID or querystring,
http://www.asp.net/mvc/videos/aspnet-mvc-2-areas
Hope this makes sense.
I want to use django's admin filter on the list page.
The models I have are something like this:
class Location(model):
name = CharField()
class Inquiry(Model):
name = CharFiled()
location = ManyToManyField(Location)
Now I want to filter Inquiries, to display only those that contain relation to specific Location object. If I use
class InqAdmin(ModelAdmin):
list_filter = ['location', ]
admin.site.register(Inquiry, InqAdmin)
the admin page displays me the list of all Locations and allows to filter.
What I would like to get, is to get list of only those locations that have some Inquiries in relation to them (so I don't ever get the empty list result after filtering).
How can this be done?
You could create a custom manager for Locations that only returns Locations that have an Inquiry associated with them. If you make this the default manager, the admin will use it.
Only caveat is that you'll need create another manager that returns all Locations and use that in the rest of your app whenever you want to retrieve Locations that don't have an associated Inquiry.
The managers section in the Django docs is quite good, and should be all you need to get this set up.
EDIT:
sienf brings up a good point. Another way to accomplish this would be to define a subclass of django.contrib.admin.SimpleListFilter, and write the queryset method to filter out Inquiries with empty Locations. See https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
I am making a django site to showcase children's clothing. You start with an overview page where you see a listing with all the clothes. In a side bar you have the following options to refine your search:
clothes for:
boys
girls
clothes in:
cotton
wool
clothes in size:
56
62
68
74
80
86
92
98
104
110
116
clothes with the color:
white
black
red
green
blue
yellow
So, suppose the user is interested in boys clothes. She clicks on 'boys', and gets served the clothes_boys view at the URL websitename.com/clothes/boys/. On that page the sidebar lists the options for fabric, size and color. The user can then drill down further to for example /clothes/boys/cotton/56/white to get a listing of all the available white cotton boys' clothes in size 56.
I have the regexes and the views for the above scenario. But the user can off course take hunderds of different paths, like /clothes/red/wool/girls/92/ and so on.
How do I go about catching all those different cases without having to manually write each of those multitude of regexes and views.
Solution 1:
Use /gender/type/size/color/ and have some kind of reserved value for unspecified - let say na. so if the user first clicks "red", he'll go to /na/na/na/red/. This way you only need 1 regex, and your urls are consistent.
Solution 2:
use GET params for this. everything is in the url /clothes/, but you can specify /clothes/?gender=boys&size=55&color=red etc. It's easy enough to parse these values in the view (request.GET['gender']). In this solution, unspecified values are just unspecified (like type in my example).
Solution 3:
Use Django-filter - its a pluggable app that implements solution 2.
My first reaction to this problem would be a middleware solution combined with some common SEO practices. Because you have a fairly narrow field of options in your URL schema, this can be a viable option.
The middleware would be responsible for performing two actions on each request.
Parse request.path looking for the pieces of your url.
Create a URL that is specific for the gender/size/color/material.
Quickly hacking something together, it may look something like this:
class ProductFilterMiddleware:
GENDERS = ("girls", "boys")
MATERIALS = ("cotton", "wool", "silk")
def proc_url(self, path):
""" Process a path looking for gender, color, material and size. """
pieces = [x for x in path.split('/') if x != '']
prod_details = {}
for piece in pieces:
if piece in self.GENDERS:
prod_details['gender'] = piece
elif piece in self.MATERIALS:
prod_details['material'] = piece
elif re.match(r'\d+', piece):
prod_details['size'] = piece
else:
prod_details['color'] = piece
return prod_details
def get_url(self, prod_details):
""" Parse the output of proc_url() to create the correct URL. """
pieces = []
if 'gender' in prod_details:
pieces.append(prod_details['gender'])
if 'material' in prod_details:
pieces.append(prod_details['material'])
if 'size' in prod_details:
pieces.append(prod_details['size'])
if 'color' in prod_details:
pieces.append(prod_details['color'])
return '/%s/' % '/'.join(pieces)
def process_view(self, request, view_func, args, options):
request.product_details = self.proc_url(request.path)
request.product_url = self.get_url(request.product_details)
This would allow arbitrary links to be created to your products without your advanced knowledge, allowing the system to be flexible with its URLs. This also includes partial URLs (just a size and material, show me all the color choices). Any of the following should be parsed without incident:
/56/cotton/red/boys/
/cotton/56/
/green/cotton/red/girls/
/cotton/
From here, your view can then create a list of products to return using request.product_details as its guide.
Part two of this solution is to then include canonical tags in each of the pages you output. This should prevent duplicate content from adversely affecting your SEO.
<link rel="canonical" href="http://www.example.com/{{ request.product_url }}" />
Warning: Google and other search engines may still hammer your site, requesting information from each URL that it can find. This can create a nasty load on your server very quickly. Because content is available from so many different locations, the spider may dig around quite a bit, even though it knows that only one copy of each page is the real deal.
One disadvantage of having multiple paths like you've specified is that search engines are going to see each page as a distinct permutation - which might hurt SEO.
I've also seen bad spiders essentially DOS-attack a site in situations like this.
This is a yucky problem that you might be best served by implementing the simplest solution possible. To my eyes, Ofri's first solution is that, except NA is kind of an ugly placeholder. Something that'll look better to the eyes might be "ALL_GENDERS", "ALL_SIZES", "ALL_TYPES". That way, you can grok things from the url, instead of having it look like it's in some kind of error state.