namespacing with js prototype framework - prototypejs

When you create a class in the name space of example.
em.components.grid
em.components.grid.Popup = Class.create(
{
initialize: function(params){
...
},
show:function(){
// create or show
}
});
Does this mean in other classes I have access to the show method if I use the namespace path above.
// Another class in prototype
em.components.grid.Popup.show();
Or does your new class your trying to access show from have to be in the same namespace.
Is namespacing kind of like packages in other languages. So by giving a namespace you can keep all your classes related to for example grid in one name space and possible other classes unrelated to grid in another namespace.
Update
This raises 2 other questions, lets say i create my class like above with the same namespace. Then in another js document I instantiate the class
var popup = new em.components.grid.Popup()
Then popup would be a global variable not? which I don't want to have in my files if possible. Seen as I have went to all the trouble of giving it a unique name space. To then create an instance of the class on a global variable somewhere else in a js file.
So in the case of a popup is it best to have it global or would it be best to create it on a rollover event and remove it on a rollout event.
//pseudo code
$$('domelementClass').observe('mouseover', function(event) {
var popup= new em.components.grid.Popup(event.target);
})
the issue I see with above is I have no reference to remove it on the rollout.
$$('domelementClass').observe('mouseout', function(event) {
popup.remove();
})

Namespacing has the same purpose of packaging, avoiding collision. As your example above shows, in JavaScript, you namespace functions and variables by making them properties of an object.
Does this mean in other classes I have access to the show method if I
use the namespace path above.
// Another class in prototype em.components.grid.Popup.show();
In this case no because 'show()' is an instance method, it can only be called once you have a new Popup. You can use your namespaced Popup as an instance in another class or if you want to call show like a static method in Java then you would call Popup.prototype.show();
var Popup = Class.create({
initialize: function(params){
alert("I exist");
},
show:function(){
alert("show!");
}
});
// Popup.show(); // would error:
// Uncaught TypeError: Object function klass() {
// this.initialize.apply(this, arguments);
// } has no method 'show'
Popup.prototype.show();
foo = new Popup();
foo.show();
Some useful links:
http://michaux.ca/articles/javascript-namespacing
http://blog.anselmbradford.com/2009/04/09/object-oriented-javascript-tip-creating-static-methods-instance-methods/

Related

Apply MVC pattern in ES6 for invoking methods

I am using the Model-View-Controller framework to structure my files for readable, reusable, and refactorable purposes.
My goal is to invoke methods from two seperate classes while working with one class. In practice; I want to access the methods for example in file Model.js and View.js from Controller.js.
Previously in ES5 I've had one file called app.js that used the IIFE approach:
var View = (function(){
dump(){
console.log('Hello World');
}
});
var Model = (function(){
// Code goes here
});
var Controller = (function(viewCtrl, viewCtrl){
viewCtrl.dump(); // Invoke method from View
})(View, Model);
As shown above, I would like to do something similar in ES6 too.
import View from './View';
import Model from './Model';
class Controller {
dump(){
return viewCtrl.dump();
}
init(){
console.log('Application has started');
// Make a new object of the class { View, Model }
let view = new View();
let model = new Model();
}
}
export default Controller;
In my main.js:
import Controller from './Controller';
// Make a new object of the class Controller
let controller = new Controller();
// Instantiate App
controller.init();
console.log(
controller.dump()
);
But doing so in ES6 I get error: ReferenceError: viewCtrl is not defined in main.js.
I was thinking perhaps pass View.js and Model.js as arguments in a constructor inside the Controller.js in order to declare them. But I guess it might be a better solution that looks cleaner.
So what I am basically looking for is to apply the MVC pattern using ES6, any recommendations?
Passing the instances of View and Model to the constructor of Controller is a clean solution since this would fullfill the dependency-injection-pattern.
This way you get the ability to change the instances from outside which makes the Controller testable.
In a situation where View and Model where singletons you could export them as instances instead of classes like
View.js:
export default new View();
Controller.js:
import view from "./View";
...
view.dump()
Using this way you could spare the work of passing a model and a view to a Controller manually but that would also mean that you loose the ability to test Controller or to change parts of it, like the View. Since this is one of the best advantages of the MVC-pattern, I would not recommend to import singletons. Instead I would recommend to inject View and Model using a constructor.

Getting view to use correct region automatically

As mentioned in an earlier question of mine, I'm new to ATK4 and I'm currently learning, so there might come a few more question. Now to my issue.
I've created a region "Sidebar" in my template shared.html and adding the view to it like this:
class Frontend extends ApiFrontend {
function init(){
parent::init();
/*
Other stuff here
*/
$this->addLayout('Sidebar');
}
function layout_Sidebar() {
$this->add('View_Menu', null, 'Sidebar');
}
}
Then I'm creating the view like this:
class View_Menu extends AbstractView {
function init(){
parent::init();
$this->add('HtmlElement')
->setElement('a')
->setAttr('href', 'testurl')
->set('Link');
}
}
This gives me the following error:
Spot is not found in owner's template
Additional information:
spot: Content
Supplying the add function with $this->template->top_tag as third argument solves this problem:
$this->add('HtmlElement', null, $this->template->top_tag)
->setElement('a')
->setAttr('href', 'testurl')
->set('Link');
...but do I really have to add that to every add() call in the view? It doesn't seem right and I'm quite sure it's not!
When you are creating AbstractView, you need to specify a default template. By default your AbstractView will use the region of from your shared.html. In other words AbstractObject assumes the template of the region it replaces.
when you create defaultTemplate() or pass 4th argument to the add() you can specify a different file to be used for template of your sidebar menu.
In either way - the template should contain a where output of any sub-elements will be displayed.
You may inherit from "View" class which already relies on the custom template containing just a . Your idea of using HtmlElement is just like this, because HtmlElement extends View.

Backbone.js Inherit Views

I have a FormView which handles such events as save and cancel. I also have an AjaxFormView that handles save, cancel and get form by ajax. I have an AssetFormView that handles save, cancel, get by ajax, delete, and print.
So on and so forth. there is considerable repitition.
I found a post this post http://kalimotxocoding.blogspot.com/2011/03/playing-with-backbonejs-views.html
where he shows you can extend views. However, I'm finding that when i have multiple versions of views on the page there are properties cross pollinating. Is there no built in way to inherit views in backbone, that is safe?
Thanks,
Raif
* hmmm well, this stuff is pretty thick and my current cross pollination issue may be ( probably is ) the result of some error on my part, but the question still stands, is there not and would it not be an important feature to have, some way to inherit views?
I'd like to see what you mean when you say that your properties are cross-pollenating.
The View.extend mechanism works quite well. Do be aware, though, that you are extending one prototype with new functions. With prototypical inheritance, the prototype shares it's objects with the new instances.
I am guessing that when you say that your properties are "cross-pollenating", you are actually doing something like this:
var baseModel = Backbone.Model.extend({
defaults: {
foo: { bar: "baz" }
}
});
Since the objects are shared, every instance of baseModel ends up having the same object for foo, giving the feeling of cross-pollination.
If instead, you define your defaults as a function, then each instance will get it's own copy of the foo object and your cross-pollination goes away.
var baseModel = Backbone.Model.extend({
defaults: function() { return {
foo: { bar: "baz" }
} }
});
Of course, without code, we can't be certain to what your problem is. Just know that this mechanism has been well-used among the community without trouble. It is safe. You just need to understand what is going on.
I'm not sure if this is the same problem you're having but I wanted to have some events defined in the parent class and then have the child class extend the property without overriding it.
If I did it like this, I was overriding what the parent defined:
App.parent = Backbone.View.extend({
events: {
'click #button-add': 'onAddButtonClicked'
'click #button-delete': 'onDeleteButtonClicked'
}
onAddButtonClicked: function() {
console.log('onAddButtonClicked');
},
onDeleteButtonClicked: function() {
console.log('onDeleteButtonClicked');
}
});
App.child = App.parent.extend({
initialize: function() {
// This looks redundant but it seems to protect App.parent::events
this.events = _.extend({}, this.additionalEvents, this.events);
// THIS IS WRONG and results in errors when I have multiple childdren:
_.extend(this.events, this.additionalEvents); // <-- this seems to change the parent
}
additionalEvents: {
'click #button-additional': 'onOtherButtonClicked'
},
onOtherButtonClicked: function() {
console.log('child:onOtherButtonClicked');
}
});
When extending the parent's events like this:
_.extend(this.events, this.additionalEvents);
I'd get "Uncaught Error: Method 'onOtherButtonClicked' does not exist" because I was modifying App.parent's events field. App.child2 was blowing up because it couldn't see the events that were put there by App.child.
By changing it to:
this.events = _.extend({}, this.additionalEvents, this.events);
I was able to protect the parent.

Extjs 4 MVC loading a view from controller

Ok so I have a controller with a method in which I want to load a view.
How do I load a view from a controller?
How do I pass some parameters from the controller to the view when I load it?
Any help is much appreciated.
To load a view, you can use Ext.widget(). Use Ext.define() to create a view in your view file. I would recommend using the alias property to define an inline xtype for the view.
When you need to load the view, you create an view using Ext.widget() and specify the xtype (alias for your view). Here is an example:
// define a window
Ext.define('MyApp.view.user.Add',
extend: 'Ext.window.Window',
alias : 'widget.adduser',
.
. // Add other properties, custom properties, methods, event handlers etc..
});
Now, when you want to create an instance in your user controller, you do:
// create an instance
var view = Ext.widget('adduser'); // refer the below note!
Note: note that there is no 'widget.'! it automatically gets added to the widget name you pass.
Now, taking about passing parameters. Like Ext.create method, you should be able to pass any parameters as:
// create an instance with params
var view = Ext.widget('adduser', {title: 'New User title'});
Regarding ref: refs help you in getting references to Views on your page. They do not help in creating an instance or load a view. If you have your view rendered, you can make use of the ref system to get hold of that instance and manipulate the view. You need to make use of the ComponentQuery to get reference of your view.
refs can be used to create new instances as well as access existing ones. By adding the option autoCreate: true to your ref, a call to the getter will result in a new instance being created using the ref definition as its config if no existing component matches the selector.
refs: [{
ref: 'list'
,selector: 'myusersgrid#users'
,autoCreate: true
// any additional options get passed as config when an instance needs to be created
,xtype: 'myusersgrid'
,itemId: 'users'
,store: 'Users'
,title: 'Users'
},{
ref: 'otherList'
,selector: 'myusersgrid#administrators'
,autoCreate: true
// any additional options get passed as config when an instance needs to be created
,xtype: 'myusersgrid'
,itemId: 'administrators'
,store: 'SpecialUsers'
,title: 'Special Users'
}],
Notice the use of the # to additionally match the itemId so I could have refs to multiple instances of the same xtype
There's also a forceCreate: true option which will make the ref's getter always return a new instance, without it autoCreate will create one instance the first time it's retrieved and then keep returning the same one.
If I understand your question I think you want to use refs, take a look at the docs for Ext.app.Controller: http://dev.sencha.com/deploy/ext-4.0.0/docs/api/Ext.app.Controller.html
Basically you create a list of refs using css selectors:
refs: [
{
ref: 'list',
selector: 'grid'
}
],
Then later in the class you can access this ref by using get, i.e.:
refreshGrid: function() {
this.getList().store.load();
}
The getList() method is created for you when you create the ref to 'list'.
I ran into this same problem. I created a method on my abstract base controller to retrieve the view instance and create on if it does not exist.
This will work properly even after the view has been destroyed - a new one will be created.
Ext.define('My.controller.Base', {
extend: 'Ext.app.Controller',
//Retrieves an instance of the top-level view
//If it has not been created yet than one is instantiated
//Also, overrides the .close() method on the view to
//null out the instance reference on the controller (very necessary)
getViewInstance: function () {
var self = this;
if(!this.viewInstance) {
if(this.views && this.views.length) {
var view = this.getView(this.views[0]);
this.viewInstance = view.create();
this.viewInstance.close = function () {
view.prototype.close.apply(this, arguments);
self.viewInstance = null;
};
}
}
return this.viewInstance;
}
});
Now all my controllers can easily access their view from w/i controller code w/o any external variables.
Use Ext.create('Proper File Name to be opened',param1 = me);
In the newly created view, use this.param1 to access the parameters.
EG: Ext.create('view.HelloOverlay, param1 = "Hello", param2 = "World");
in the controller of HelloOverlay, using this.param1 will give "Hello" and this.param2 will give "World".
Sometimes the parameters passed will be present in the view so use this.getView().paramName

Passing Instance to Shared Method in VB.NET

I have been thrown in at the deep end with an existing VB.NET project at work. I have never used VB.NET before so I am struggling a little. Does anyone know how to solve the following.
I need to pass an instance to client side and then pass it to a shared method in order to access instance methods from when the shared method.
The starting point is a fileupload control within the HTML of my Contacts.aspx file:
<asp:FileUpload ID="DocUpload1" runat="server" onchange="CallMe();" />
The onchange event calls a javascript method, see below, this uses AJAX PageMethods to called a Shared method in my code behind
This is the script code which is in my Contact.aspx file
<script language="javascript">
function CallMe() {
// call server side method
PageMethods.GetContact(0, CallSuccess, CallFailed, null);
}
// set the destination textbox value with the ContactName
function CallSuccess(res, destCtrl) {
}
// alert message on some failure
function CallFailed(res, destCtrl) {
alert(res.get_message());
}
</script>
This is an example class of the type of thing I want to do, I think I need to use the "instance As Contacts" as an input parameter to the WebMethod function but I don't know how to pass the instance into it:
This is the class within my Contacts.aspx.vb file.
Partial Class Contacts
<System.Web.Services.WebMethod()> _
Public Shared Function GetContact(ByVal instance As Contacts) As String
Return instance.GetContactName() 'This is an instance class which I need to call.
End Function
'This is my instance class which I want to call from the Shared Class.
Public Shared Function GetContactName() As String
Return "Fred Bloggs"
End Function
End Class
If anyone knows the solution please could they update the code as I probably won't be able to understand if you just give a description. I just hope I am along the right tracks.
If I understand you correctly, you want to access a class (your instance) created in the ASP.Net page life-cycle from your PageMethod - eg created during initial page load or file upload etc.
This is not directly possible as PageMethods do not go through the full page life-cycle (they are essentially webservices). So you need to pass some sort of identifier to the client that, when passed back to the server in the PageMethod, can be used to re-create or retrieve your instance.
eg During the initial page load:
session("ContactID") = instance
Your PageMethod might look something like:
Public Shared Function GetContact(ByVal key As String) As String
Return HttpContext.Current.Session(key).GetContactName()
End Function
where the parameter key is the same key you used to store your instance in the session state.
In your javascript:
function CallMe() {
// call server side method
PageMethods.GetContact('ContactID', CallSuccess, CallFailed, null);
}

Resources