Adding Scripts to Nop Commerce plugin - plugins

I am trying to add bootstrap to a Payment Plugin that I am developing and I do not know why it's not including the files in OnePageChekout page that includes the PaymentInfo.cshtml partial view...
Code:
#model Nop.Plugin.Payments.PluginName.Domain.PluginModel
#{
Layout = "";
Html.AddScriptParts("~/Plugins/Payments.PluginName/Scripts/bootstrap.min.js");
Html.AddCssFileParts("~/Plugins/Payments.PluginName/Content/bootstrap.min.css");
}
#using Nop.Web.Framework.UI
Tried this as well:
#model Nop.Plugin.Payments.PluginName.Domain.PluginModel
#{
Layout = "";
Html.AddScriptParts(ResourceLocation.Foot,"~/Plugins/Payments.PluginName/Scripts/bootstrap.min.js", true);
Html.AddCssFileParts(ResourceLocation.Head, "~/Plugins/Payments.PluginName/Content/bootstrap.min.css");
}
#using Nop.Web.Framework.UI
Tried to use Html.AppendCssFileParts and Html.AppendScriptFileParts and it did not worked.
When debugging...the code calls this functions and it's adding the file references to the _scriptsParts and _cssParts variables.
But at that moment it adds my scripts those variables do not have any more scripts which I think it's odd.
Also it never calls the GenerateCssFiles function which I think is the function that adds the scripts to the bundle because this is only called after the page (OnePageCheckout.cshtml) is loaded and never when a partial view is loaded in the main view.
Am I right in this assumptions ? How can I add scripts dynamically to the PaymentInfo.cshtml page ?

Related

Nested View in Theme Views using Fuelphp

I have working with Fuelphp and done some tiny apps, Now i am moving to bigger one, now i am stuck with this.
I have enabled theme in fuelphp and it is working perfectly, In my App there is a Top Nav bar, In Nav bar there is 3 drop down notification system like facebook & also search option. So i have created top_nav partial. I want to make the search and notification system in partial inside partial, to making it more modular, so i created another partial of top_nav_search and top_nav_notif . Both partials need some variables to transfer from controller, How i do that. My variables are passing to top_nav only. Not top_nav_search or top_nav_notif.
How can i add partial inside the partial.
Answer Found:
using View Class will not work with theme. It will search for APP/View folder.
we have to use
echo Theme::instance()->view('partials/partial_file')->set_safe('var', $this->get('var'));
found working
You can use set_global on your view, and then the exposed variable will be available everywhere.
$view->set_global('some_data', $some_data);
// instead of
$view->some_data = $some_data;
Also, when using set_partial, you can specify a View instance instead of the path for the view. That way you can pass variables directly into the View instance specified to set_partial. Though I'm not sure it solves your problem. Still, here's an example:
$view = View::forge('nav/search');
$view->some_data = $some_data;
$theme->set_partial('top_nav_search', $view);
Edit: I wrote View::forge, but more appropriate would've been to write $theme->view in this example. Like this:
$view = $theme->view('nav/search');
$view->some_data = $some_data;
$theme->set_partial('top_nav_search', $view);

What is the proper way to integrate dynamic content into the layout.ejs file in a Sails.JS application?

Say I wrote a blog app in Sails.js.
On every page in this app, there is a sidebar widget called "Recent Posts", where it lists the titles of the 5 most recent posts and clicking on them takes you to the post in question.
Because this sidebar widget is present on every page, it should be in layout.ejs. But, here we have a conflict - dynamic content is only supposed to be pulled from the database in the controller action for rendering a specific view.
This dynamic content isn't for a specific view, it's for the whole site (via layout.ejs).
By the conventions that I understand, I'd have to get that dynamic content data for the sidebar widget in every controller action that renders a view (otherwise I would get an undefined error when I attempt to call that local in my layout.ejs file).
Things I've tried / considered:
Load that dynamic content in every controller action that renders a view (this solution is very bad) and calling that dynamic content in layout.ejs as if it were a local for the specific view. This works fine, but goes against D.R.Y. principles and quite frankly is a pain in the ass to have to run the same query to the database in every controller action.
As per another similar stackoverflow question, create a new config (E.G. config/globals.js), load my dynamic content from my database into that config file as a variable, and then calling sails.config.globals.[variable_name] in my layout.ejs file. This also worked, since apparently config variables are available everywhere in the application -- but it 's a hacky solution that I'm not a fan of (the content I'm loading is simply the titles and slugs of 5 recent posts, not a "global config option", as the solution implies).
Run the query to get the dynamic content inside the .EJS file directly between some <% %> tags. I'm not sure if this would work, but even if it did, it goes against the separation of concerns MVC principle and I'd like to avoid doing this if at all possible (if it even works).
As per a lengthy IRC discussion # http://webchat.freenode.net/?channels=sailsjs, it was suggested to create a policy and map that policy to all my controllers. In that policy, query the database for the 5 most recent posts, and set them to the req.recentposts. The problem with this solution is that, while the recent posts data will be passed to every controller, I still have to pass that req.recentposts data to my view -- making it so I still have to modify every single res.view({}) in every action. I don't have to have the database query in every action, which is good, but I still have to add a line of code to every action that renders a view... this isn't D.R.Y. and I'm looking for a better solution.
So, what is the proper solution, without needing to load that dynamic content in every controller action (a solution that adheres to D.R.Y. is what I'm lookng for), to get some dynamic content available to my layout.ejs file?
In folder /config you should create a file express.js and add something like that:
module.exports.express = {
customMiddleware: function(app){
app.use(function(req, res, next){
// or whatever query you need
Posts.find().limit(5).exec(function(err, posts){
res.locals.recentPosts = posts;
// remember about next()
next();
});
});
}
}
Then just make some simple loop in your view:
<% for(var i=0; i<recentPosts.length; i++) { %>
<% recentPosts[i].title %>
<% } %>
Here are some links to proper places in documentation:
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Configuration.md#express
and
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Response.md#reslocals
I found out another way to do this. What I did was to create a service that could render .ejs files to plain html by simply taking advantage of the ejs library already in sails. This service could either be invoked by the controller, or even passed as a function in the locals, and executed from within the .ejs. The service called TopNavBarService would look like:
var ejs = require('ejs');
exports.render = function() {
/* database finds goes here */
var userInfo = {
'username' : 'Kallehopp',
'real_name' : 'Kalle Hoppson'
};
var html = null;
ejs.renderFile('./views/topNavBar.ejs', {'locals':userInfo}, function(err, result) { html = result; });
return html;
}
In the constroller it could look like:
module.exports = {
testAction: function (req, res) {
return res.view('testView', {
renderNavbar: TopNavBarService.render // service function as a local!
});
}
};
This way you can create your customized ejs-helper that could even take arguments (although not shown here). When invoked, the helper could access the database and render a part of the html.
<div>
<%- renderNavbar() %>
</div>

Call Modules Controller from Application Bootstrap

I've asked a question like this previously but I believe this is different (that one was just a general question).
I implemented Zend_Navigation.
For menu I used DB Table to store menu items and did recursion on Array-s to get the tree of menu items.
All of this action takes place in my module called Menu. Inside I have:
Menu --
Controllers --
IndexController.php
Models--
DbTable--
Menu.php
Bootstrap.php
inside index controller I have a function menuGenerator($menu_id)
So following tutorials on Zend_Navigation, the menu is initialized in the application bootstrap.
my function inside application's bootstrap looks like this:
public function _initMenus() {
$menuArray = new Menu_IndexController();
$outArray = $menuArray->menuGenerator(1);
$mainmenu = new Zend_Navigation($outArray);
$this->view->navigation($mainmenu);
}
and it gives me an error:
Fatal error: Class 'Menu_IndexController' not found in D:\Server\xampp\htdocs\project\application\Bootstrap.php on line 8
So, Any ideas how should I make it to work correctly?
P.S. is it possible to start 2 new menus at a time? for ex: I need 1. main menu 2. footer menu (any link to an article would be nice)
By default, Zend Framework's autoloader doesn't autoload controllers in the same way it loads other components (models, view helpers, forms, etc), so PHP throws the error saying it can't find the class. The quickest way to get around this is to explicitly include the controller in Bootstrap.php. The following should work:
public function _initMenus() {
require_once('./Controllers/IndexController.php');
$menuArray = new Menu_IndexController();
$outArray = $menuArray->menuGenerator(1);
$mainmenu = new Zend_Navigation($outArray);
$this->view->navigation($mainmenu);
}
It's pretty unusual to call a controller method during Bootstrap since there are many bootstrapping tasks upon which controller actions depend. In your case, the controller method menuGenerator() is not actually an action, so presumably it will not be a problem.
Nonetheless, it's still unusual enough that I would move the menuGenerator() method out into its own class. Then invoke that operation both at Bootstrap and in your controller.

How do I avoid repetition when passing variables from the Controller/Action to the Layout

I am currently working on a project developed using Zend Framework, based on the structure of my web page design I have reached a point where I have to pass a small number of variables to my layout from each Controller/Action. These variables are:
<?php Zend_Layout::getMvcInstance()->assign('pageId', 'page1'); ?>
<?php Zend_Layout::getMvcInstance()->assign('headerType', '<header id="index">'); ?>
The reason for passing this information is firstly, I pass the page id as the multi column layout may change depending on the content being displayed, thus the page id within the body tag links the appropriate CSS to how the page should be displayed. Secondly I display a promotional jQuery slider only on the index page, but I need the flexibility to have it displayed on potentially multiple pages in case the wind changes and the client changes their mind.
My actual question: Is there a more appropriate method of passing this information to the Layout that I am overlooking?
I am not really questioning whether the information has to be sent, rather is there some Zend Framework feature that I have, in my haste, overlooked which would reduce the amount of repetitive redundant code which may very well be repeated in multiple Actions within the same controller?
You could turn that logic into an action helper than you can call from your controllers in a more direct way. You could also make a view helper to accomplish the same thing but view helpers usually generate data for the view rather than set properties.
// library/PageId.php
class Lib_PageId extends Zend_Controller_Action_Helper_Abstract
{
public function direct($title, $pageId, $headerType)
{
$view = $this->getActionController()->view;
$view->headTitle()->append($title);
$view->pageId = $pageId;
$view->headerType = $headerType;
}
}
In your controller actions you can now do this:
$this->_helper->PageId('Homepage', 'page1', 'index');
// now pageId and headerType are available in the view and
// Homepage has been appended to the title
You will also need to register the helper path in your Bootstrap like this:
protected function _initActionHelpers()
{
Zend_Controller_Action_HelperBroker::addPrefix('Lib');
}
Doing it like that can reduce the amount of repetitive code and remove needing to assign the values from the view. You can do it in the controller very quickly. You can also have default values in the case that the helper hasn't been called.
You shoudn't really be passing anything from the view to the layout, for a start the view should be included IN the layout, not the other way around.
So, setting your page title should be done using similar code to what you have, but inside the controller action being called:
$this->view->headTitle()->append('Homepage');
And the other two issues - you need to rethink as I stated to begin with. Maybe you're misunderstanding the layout/view principle? If you include the different views per action, then you simply change the div id when needed, and include the header for your banner only in the index.phtml file.

dojo.data is undefined Flitering select

I am having a few problems with Dojo Filtering Selects when using the Zend Framework Forms and need some help to find out what I have missed as this is driving me mad.
I am currently getting this errors in firebug:
dojo.data is undefined
dojo.data.ItemFileReadStore is not a constructor
Below is the code that I am using to create the filter select and provide the json data to the calling controller.
Zend_Form Element (Dojo Enabled)
$industry = new Zend_Dojo_Form_Element_FilteringSelect('industry');
$industry->setAutocomplete(true)
->setStoreId('industrystore')
->setStoreType('dojo.data.ItemFileReadStore')
->setStoreParams(array('url' => $baseUrl.'/dojo/industry'))
->setAttrib("searchAttr", "title")
->setRequired(true)
->removeDecorator('DtDdWrapper')
->removeDecorator('label')
->removeDecorator('HtmlTag');
Dojo Controller
public function industryAction(){
$db = Zend_Db::factory($this->config->database);
$result = $db->fetchAll("SELECT * FROM industries");
$data = new Zend_Dojo_Data('industryid', $result);
$this->_helper->autoCompleteDojo($data);
$db->closeConnection();
}
The annoying thing is all my other Dojo elements on this form and other forms work well it is just whenever I do Filtering Selects that I hit these problems, and this problem causes all the other elements in a form to fail too.
Thanks in advance.
The problem is actually with how Zend Framework initializes the dijits and data stores before the toolkit is fully loaded, in this case specifically the methods assigning the store to the dijit. I ran into this issue as well and found the best way to work around the issues was to either pass the data store from the controller to a JavaScript variable defined in the view or do what your did with a specific autocomplete action. Based on your example I would make the following changes.
In your form I would simplify the element:
$industry = new Zend_Dojo_Form_Element_FilteringSelect('industry');
$industry->setAutocomplete(true)
->setRequired(true)
->removeDecorator('DtDdWrapper')
->removeDecorator('label')
->removeDecorator('HtmlTag');
In your view you want to connect the store to your dijit and make sure that you have loaded the dojo.data.ItemFileReadStore module:
<?php $this->dojo()->onLoadCaptureStart()?>
function(){
dijit.byId('industry').store = new dojo.data.ItemFileReadStore({ url: '/controller/industry' });
}
<?php
$this->dojo()->onLoadCaptureEnd();
$this->dojo()->requireModule('dojo.data.ItemFileReadStore');
?>
As I mentioned I ran into a similar issue which I answered here . Another issue I discovered is that the data store does not like dealing with labels declared anything other than "name" for the label declaration in the Zend_Dojo_Data.