I'm trying to make a composition UI for a small website.
My building tree looks like this:
Shell (Conductor.Collection.AllActive)
Contains multiple IPod's (you can view them as small widgets)
1 Pod is a PagePod.
This last one is of sort IPodConductor, so a combination of a Screen ( the pagepod ) containing IPage (like MainPage, ContactPage .. )
My whole construction can find all my viewmodels and views following Caliburns convention, but not my MainPage.
The error is as following:
"Cannot find view for Gymsport.Client.Pages.Main.MainPageViewModel"
My structure to the view is as following:
Gymsport.Client.Pages.Main.MainPageView
Following the convention, caliburn should be able to locate my view... but it doens't.
Anybody any tips on to figure out or pointers for debugging this error.
Thanks in advance.
In C.M, there is additional logic for finding Views concerning words like Page, etc. (see here).
So you can either change your views to match the rules in C.M, remove word Page from your view models, or you can enforce custom simple view location with something like that:
ViewLocator.LocateTypeForModelType = (modelType, displayLocation, context) =>
{
var viewTypeName = modelType.FullName.Substring(
0,
modelType.FullName.IndexOf("`") < 0
? modelType.FullName.Length
: modelType.FullName.IndexOf("`")
);
viewTypeName = viewTypeName.Replace("Model", string.Empty);
if (context != null)
{
viewTypeName = Regex.Replace(viewTypeName, "View$", string.Empty);
viewTypeName += "." + context;
}
var viewType = (from assembly in AssemblySource.Instance
from type in assembly.GetExportedTypes()
where type.FullName == viewTypeName
select type).FirstOrDefault();
return viewType;
};
Related
I have a form_templates table and a forms table. They're connected by form_template_id. I want to be able to list the form_templates that have been created by title within a select.ctp file I have created within the Forms controller. Just wanting some direction on how to do this with cakephp?
At the moment I have the following code within my FormsController:
public function select()
{
$this->set('page_heading', 'Current Forms');
$contain = [];
$formTemplate = $this->FormTemplates->Forms->find('list', ['order' => 'title'])->where(['active'=>true]);
$forms = $this->paginate($this->Forms->FormTemplates);
$this->set(compact('forms', 'formTemplate'));
}
But I am getting a Call to a member function find() on null error.
Any help on how to tackle this would be greatly appreciated. I know it would be simple but I am new to cakephp.
In your FormsController only FormsTable is loaded automatically, and you are trying to access model that is not currently loaded:
$formTemplate = $this->FormTemplates->Forms->find(...
To get what you want, you should access associated FormTemplatesTable like this:
$formTemplate = $this->Forms->FormTemplates->find(...
I've two controllers one is "Upload" which deals with images uploads and other is "Page" whid deals with the creation of pages of CMS now if in my "Upload" controller I load both the models i.e 'image_m' which deals with image upload and "page_m" which deals with the pages creation I've highlighted the relevant code my problem is if I access the variables in the view
$this->data['images'] = $this->image_m->get(); sent by this I can access in foreach loop as "$images->image_title, $images->image_path" etc
But the variable sent by this line ***$this->data['get_with_images'] = $this->page_m->get_no_parents();*** as $get_with_images->page_name, $get_with_images->page_id etc produces given error
A PHP Error was encountered
Severity: Notice
Message: Trying to get property of non-object
Filename: upload/index.php
Line Number: 20
what is the difference between these two access levels one for $image & other for $get_with_images because I can only access its values as $get_with_images
class Upload extends Admin_Controller {
public function __construct() {
parent::__construct();
***$this->load->model('image_m');
$this->load->model('page_m');***
}
public function index($id = NULL) {
//var_dump($this->data['images'] = $this->image_m->get_with_images());
//$this->data['images'] = $this->image_m->get_with_images();
***$this->data['images'] = $this->image_m->get();***
$this->data['subview'] = 'admin/upload/index';
if ($id) {
$this->data['image'] = $this->image_m->get($id);
count($this->data['image']) || $this->data['errors'][] = 'Page Could not be found';
}
$id == NULL || $this->data['image'] = $this->image_m->get($id);
/*this calls the page_m model function to load all the pages from pages table*/
***$this->data['get_with_images'] = $this->page_m->get_no_parents();***
You are not posting all your code so its hard to tell but is it because you used $this-> in the controller, but you haven't done the same thing in the view?
In this case i would recommend not using $this-> because its not necessary. Also its much better to check for errors etc when you call the model so do something like
if ( ! $data['images'] = $this->image_m->get($id) ) {
// Failure -- show an appropriate view for not getting any images
// am showing $data in case you have other values that are getting passed
$this->load->view( 'sadview', $data ); }
else {
// Success -- show a view to display images
$this->load->view( 'awesomeview', $data ); }
so we are saying if nothing came back - the ! is a negative - then show the failure view. Else $data['images'] came back, and it will be passed to the view. note i have not had to use $this-> for anything and it won't be needed in the view.
Would also suggest using separate methods - have one method to show all images and a separate method like returnimage($id) to show an image based on a specific validated $id.
====== Edit
You can access as many models as you want and pass that data to the View. You have a different issue - the problem is that you are waiting until the View to find out - and then it makes it more difficult to figure out what is wrong.
Look at this page and make sure you understand the differences between query results
http://ellislab.com/codeigniter/user-guide/database/results.html
When you have problems like this the first thing to do is make a simple view, and echo out directly from the model method that is giving you problems. Its probably something very simple but you are having to look through so much code that its difficult to discover.
The next thing is that for every method you write, you need to ask yourself 'what if it doesn't return anything?' and then deal with those conditions as part of your code. Always validate any input coming in to your methods (even links) and always have fallbacks for any method connecting to a database.
On your view do a var_dump($get_with_images) The error being given is that you are trying to use/access $get_with_images as an object but it is not an object.
or better yet on your controller do a
echo '<pre>';
var_dump($this->page_m->get_no_parents());
exit();
maybe your model is not returning anything or is returning something but the data is not an object , maybe an array of object that you still need to loop through in some cases.
The base model of my application has a status attribute.
Let's assume, for simplicity, that status might be either pending or deleted.
I have an upper menu with these two status values, when you click one of them you see all objects with this status (I use router to trigger a filter).
My problem is that I need to draw a different template for each status.
deleted object has delete forever and recover buttons
pending object has delete, edit and some other buttons (also some textarea...)
I wonder what would be the best solution for this problem.
I thought of creating a different view for each status, but then I don't know how to deal with it in the collection level.
I also thought of creating different templates and deal with it in the model-view level, but again - I have no idea whether it is possible and if yes - how.
Finally, I can solve it with same template and view, hiding what is not necessary inside the view, but then the code becomes quite ugly in my point of view.
Ideas?? Thanks!
If you want to create a different view for each status, you do it this way :
Router {
clickDeletedMenu : {
var collection = new MyCollection();
var deletedView = new DeletedView({ model : collection });
collection.fetch({ status : 'deleted' }); // filter deleted objects
},
clickPendingMenu : {
var collection = new MyCollection();
var pendingView = new PendingView({ model : collection });
collection.fetch({ status : 'pending' }); // filter deleted objects
},
}
If you want to create differents templates, you do it this way :
View {
render : {
if (this.model.status == 'deleted') {
// render deleted template
} else {
// render pending template
}
}
}
Finally, in my point of view, you can use the same template and view, and hiding what is not necessary inside the template not the view.
nb : the code is used just to illustrate the idea, it's not going to execute :)
I am new to backbone.
After much confusion about not being able to add some of my models to a collection and sometimes getting the wrong model using collection.get(id) I found out that my model ids are colliding with backbones cids.
My model ids are something like "c7" or "c5e6". While the later is no problem "c7" is backbones own cid for the seventh element of the collection.
So if I ask for collection.get('c7') and expect null I instead get the element that was given the cid "c7" by backbone. And if I add an element with id "c7" I will never get it back with get("c7").
I wonder if I am the first one with this problem, I did not find anything about a syntax restriction of backbone ids, is there a way to solve this? As a workaround I will save my own ids in a custom attribute, and have to use collection.where instead of collection.get.
Any better ideas?
If you look at Backbone source code, you will see that the cid in a model is determined in the constructor by
this.cid = _.uniqueId('c');
c is an arbitrary prefix which means you could disambiguate your ids by overriding _.uniqueId, something like
_._uniqueId = _.uniqueId;
_.uniqueId = function(prefix) {
if (prefix === 'c') {
prefix = 'cc';
}
return _._uniqueId(prefix);
};
Without the override : http://jsfiddle.net/nikoshr/KmNSr/ and with it : http://jsfiddle.net/nikoshr/KmNSr/1/
Unfortunately, this does look like an edge case problem with no real solution. Looking at the Backbone source, we can see in the Backbone.Collection.set method that Backbone mixes both your IDs and their internal CIDs in the same object:
set: function(models, options) {
// ...
this._byId[model.cid] = model;
if (model.id != null) this._byId[model.id] = model;
// ...
return this;
},
The _byId object holds all IDs which causes your issue. Here is the Backbone.Collection.get method:
get: function(obj) {
if (obj == null) return void 0;
return this._byId[obj.id != null ? obj.id : obj.cid || obj];
},
When you call it using a non-existent ID (of your own) like "c7", the return ... line becomes return this._byId["c7"];. Since _byId has references to yours and Backbone's IDs, you're getting their entry returned when you expected null.
nikoshr has a great solution in the answer below.
I have set up the Display Mode in Application Start event as
DisplayModeProvider.Instance.Modes.Insert( 0, new DefaultDisplayMode( "iPhone" ){
ContextCondition = ( context =>
context.GetOverriddenUserAgent( ).IndexOf(
"iPhone",
StringComparison.OrdinalIgnoreCase ) >= 0 ) } );
Then in the controller I have return View where I specify the view name:
return View( "~/Views/Common/User/Login.cshtml", viewModel );
And if I visit the page from the iPhone it will go directly to Login View
If I do not specify the view name:
return View( viewModel );
In this case from the iPhone I see the Login.iPhone.cshtml
Question: Is it possible to specify the name of the view but some how the DisplayModeProvider will select general or iPhone version of the cshtml file?
I don't normally like to resurrect old questions but as this one was never answered and this is one I had particular trouble finding an answer to myself, it may be worth having an answer for anyone else who comes across the same problem.
You could add your additional locations to the ViewLocationFormats and PartialViewLocationFormats collections for the ViewEngines you are using. This way you could just specify the view name as tvanfosson suggests and MVC would find the file correctly, which should allow the mobile overriding to work it's magic.
Here is some code I use to override the PartialViewLocationFormats, you could also do the same using ViewLocationFormats. This is added in global.asax as part of application_start
ViewEngines.Engines.Clear();
var razorViewEngine = new RazorViewEngine
{
PartialViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/{1}/EditorTemplates/{0}.cshtml",
"~/Views/{1}/DisplayTemplates/{0}.cshtml",
"~/Views/Shared/DisplayTemplates/{0}.cshtml"
}
};
Because this method involves clearing the viewengines collection, you will need to add in all locationFormats, even the standard ones, for all the view engines you are using.