Arquitectura en Cliente con Javascript

.Net, Web Add comments

La mayoría de las veces cuando se define la arquitectura de una aplicación web solo se tiene en cuenta la parte servidor, como si el lado cliente no fuera importante o no existiera. Es verdad que en cliente disponemos de un lenguaje interpretado (no compilado), lo cual hace si cabe un poquito mas complicado el desarrollo,  al no disponer de las ventajas del pre compilado que nos ofrece Visual Studio. Además,  el ordenado del código debería ser un factor importante, ya que la tendencia es tener  un único fichero o script de código Javascritp, y esto siempre  comienza siendo unas pocas líneas para unas cuantas validaciones y va creciendo paulatinamente debido a la no planificación de la arquitectura en cliente o a nuevos requerimientos.

Atajar esto no es fácil, y el artículo no define ningún modelo de arquitectura, pero si unas cuantas pautas de buena conducta que nos ayuden a tener un condigo algo mas limpio y ordenado.

VIEW limpia

 

Lo primero es mantener nuestras paginas ASPX (o HTML) limpias en la medida de lo posible de código javascript. Un problema que solemos encontrar al intentar sacar el código a ficheros js, es el acceso a los controles de servidor, ya que no disponemos del nombre en cliente de estos. Para solventar esto, podemos generar un array que contenga el ID asociado al control como ‘key’ y el control en si como ‘value’:

JavaScript:
  1. function InitControls() {
  2. Controls["txtName"] = document.getElementById('<!--xtName.ClientID-->');
  3. Controls["txtAddress"] = document.getElementById('<!--xtAddress.ClientID-->');
  4. Controls["txtCity"] = document.getElementById('<!--xtCity.ClientID-->');
  5. Controls["txtPhone"] = document.getElementById('<!--xtPhone.ClientID-->');
  6. Controls["txtWebsite"] = document.getElementById('<!--xtWebsite.ClientID-->');
  7. }

‘Controls’ es una variable (Propiedad) definida en un fichero JS referenciado en la pagina. Este fichero hará las veces de code behind. Ahora solo tenemos que preocuparnos de llamar a la función InitControl() en el evento onLoad.

Codebehind _defalut.js

Asociada a cada pagina, podemos definir un fichero js que maneje los eventos que producen los controles de la pagina, ya sea cambiando el estado de los controles o cargando y salvando datos.

JavaScript:
  1. var Controls = new Array();
  2.  
  3. //OnClick Event Handler of GetCompany Button
  4. function btnGetClick() {
  5. var service = JavascriptClasses.webservices.jsWebService;
  6. var comp = new Company();
  7.  
  8. comp._WebService = service;
  9.  
  10. //Load Company with id=1 and set the function in charged of manage the result on the view
  11. comp.LoadCompany(1, SetValues, service);
  12. }
  13.  
  14. //OnClick Event Handler of Save Company Button
  15. function btnSaveCompanyClick() {
  16. var comp = GetCompany();
  17. var service = JavascriptClasses.webservices.jsWebService;
  18.  
  19. comp.SaveCompany(service);
  20. }
  21.  
  22. //This function is called from the Company object
  23. //when the asyncronous web service response
  24. //was recieved
  25. function SetValues(obj) {
  26.  
  27. Controls['txtName'].value = obj.Name;
  28. Controls['txtAddress'].value = obj.Address;
  29. Controls['txtCity'].value = obj.City;
  30. Controls['txtPhone'].value = obj.Phone;
  31. Controls['txtWebsite'].value = obj.WebSite;
  32. }
  33.  
  34. //Rerturn a Company Object with the form's values
  35. function GetCompany() {
  36. var item = new Company();
  37.  
  38. item.Name = Controls['txtName'].value;
  39. item.Address = Controls['txtAddress'].value;
  40. item.City = Controls['txtCity'].value;
  41. item.WebSite = Controls['txtPhone'].value;
  42.  
  43. return item;
  44. }

Clases en Javascript

 

Pues si, porque no? Una forma de organizar nuestro código es definiendo clases que nos ayuden a interactuar con la naturaleza de los objetos que definen la funcionalidad de la pagina. Por ejemplo, si tenemos una pagina que muestra los datos de una compañía, no sería descabellado tener un clase “Company” que defina ese tipo de objeto, además de ofrecer funcionalidades para trabajar con el. Tendría propiedades y metodos publicos encargados de acceder a servicios web para cargar o salvar datos.

JavaScript:
  1. function Company() {
  2. //Public Properties
  3. this.CompanyId = "";
  4. this.Name = "";
  5. this.Address = "";
  6. this.City = "";
  7. this.Phone = "";
  8. this.WebSite = "";
  9. this._WebService = "";
  10.  
  11. //Private members
  12. var _onrecieveCompanyData;
  13. var _onSaveData;
  14.  
  15. //**************
  16. //Public Methods
  17. //**************
  18. this.LoadCompany = function(companyId, OnRecieve, ws) {
  19.  
  20. if (ws)
  21. this._WebService = ws;
  22. _onrecieveCompanyData = OnRecieve;
  23. //Call Web Service
  24. if (this._WebService)
  25. ws.LoadCompany(companyId, LoadCompanyOK, LoadCompanyError);
  26. }
  27.  
  28. this.SaveCompany = function(ws) {
  29.  
  30. if (ws)
  31. this._WebService = ws;
  32.  
  33. if (!ValidateCompany())
  34. alert("Please fill mandatory fields.");
  35. else if (this._WebService) {
  36. //here you should call the web service
  37. alert("Company saved.");
  38. }
  39.  
  40. }
  41. //***************
  42. //Private Methods
  43. //***************
  44.  
  45. function LoadCompanyOK(results) {
  46. if (results) {
  47. CompanyId = results.CompanyId;
  48. Name = results.Name;
  49. Address = results.Address;
  50. City = results.City;
  51. Phone = results.Phone;
  52. WebSite = results.WebSite;
  53.  
  54. //if return function
  55. if (_onrecieveCompanyData)
  56. _onrecieveCompanyData(this);
  57. }
  58.  
  59. }
  60. function LoadCompanyError(error) {
  61. alert(error);
  62. }
  63.  
  64. function SaveCompanyOK(results) {
  65. if (results) {
  66. //if return function
  67. if (_onSaveData)
  68. _onSaveData(this);
  69. }
  70. }
  71.  
  72. function SaveCompanyError(error) {
  73. alert(error);
  74. }
  75.  
  76. function ValidateCompany() {
  77. return (this.Name.length&gt; 0 &amp;&amp; this.Address.length&gt; 0 &amp;&amp; this.WebSite.length&gt; 0);
  78. }
  79. }

Class o function

Realmente se definen de la misma forma, la diferencia radica en la forma de hacer uso de ella, bien invocándola o instanciándola.

JavaScript:
  1. function Coche(){
  2. return "BMW";
  3. }
  4.  
  5. alert(Coche()); // --&gt; Mensaje: "BMW"
  6.  
  7. alert(new Coche()); // --&gt; Mensaje: Object

Propiedades

Para definir una propiedad publica en una clase usaremos “this” y el nombre del atributo. Por el contrario si lo que queremos es definir un miembro privado lo definiremos medienate la directiva var:

JavaScript:
  1. function Coche()
  2. {
  3. this.Marca = "BMW";
  4. this.Modelo = "";
  5.  
  6. var _color = "rojo";
  7. }
  8.  
  9. var c = new Coche();
  10.  
  11. alert(c.Marca); // Mensaje: "BMW";
  12. alert(c._color); // Mensaje: undefined

Métodos (públicos o privados)

La diferencia entre que un método sea Publico o Privado a la clase la encontramos también en la directiva “this”. Con “this” realmente lo que hacemos es adjuntar propiedades o métodos al objeto, y hacemos a estos visibles fuera de la clase.

JavaScript:
  1. function Speak()
  2. {
  3. this.SayHello = function() {
  4. alert("Hello");
  5. }
  6.  
  7. function SayGoodbye(){
  8. alert("Bye");
  9. }
  10. }
  11.  
  12. var s = new Speak();
  13. s.SayHello();
  14. s.SayGoodbye(); //--&gt; Error

Cuando definimos métodos, podemos definirles parámetros, que pueden contener incluso referencias hacia funciones. Esto es útil cuando estos métodos realizan por ejemplo llamadas a servicios web, llamadas que son asíncronas y no sabemos cuando van a recibir  respuesta.

JavaScript:
  1. this.LoadCompany = function(companyId, OnRecieve, ws) {
  2. //reference to funtion that has to be called
  3. //when web service reponse is recieved
  4. _onrecieveCompanyData = OnRecieve;
  5. //Call Web Service
  6. ws.LoadCompany(companyId, LoadCompanyOK, LoadCompanyError);
  7. }
  8.  
  9. function LoadCompanyOK(results) {
  10. if (results) {
  11. ...
  12. ...
  13. _onrecieveCompanyData(this);
  14. }
  15. }

De esta manera, y una vez que la llamada al servicio web ha tenido repuesta, podemos continuar el flujo de la aplicación, ejecutando una función definida en el controlador encargada de operarar con los datos recibidos desde el servidor.

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in

Switch to our mobile site