Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #37500 > unrolled thread

A very small MVC prototype, for real this time... but need help... of course

Started byluserdroog <luser.droog@gmail.com>
First post2019-10-04 21:43 -0700
Last post2019-10-05 23:38 -0700
Articles 13 — 4 participants

Back to article view | Back to comp.lang.javascript


Contents

  A very small MVC prototype, for real this time... but need help... of course luserdroog <luser.droog@gmail.com> - 2019-10-04 21:43 -0700
    Re: A very small MVC prototype, for real this time... but need help... of course luserdroog <luser.droog@gmail.com> - 2019-10-05 12:52 -0700
      Re: A very small MVC prototype, for real this time... but need help... of course "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2019-10-05 22:52 +0200
        Re: A very small MVC prototype, for real this time... but need help... of course luserdroog <luser.droog@gmail.com> - 2019-10-05 23:26 -0700
          Re: A very small MVC prototype, for real this time... but need help... of course "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2019-10-06 11:39 +0200
            Re: A very small MVC prototype, for real this time... but need help... of course Silvio <silvio@internet.com> - 2019-10-06 16:42 +0200
            Re: A very small MVC prototype, for real this time... but need help... of course luserdroog <luser.droog@gmail.com> - 2019-10-06 11:22 -0700
              Re: A very small MVC prototype, for real this time... but need help... of course "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2019-10-06 22:25 +0200
                Re: A very small MVC prototype, for real this time... but need help... of course Jonas Thörnvall <jonas.thornvall@gmail.com> - 2019-10-06 14:15 -0700
                Re: A very small MVC prototype, for real this time... but need help... of course luserdroog <luser.droog@gmail.com> - 2019-10-06 14:25 -0700
                Re: A very small MVC prototype, for real this time... but need help... of course luserdroog <luser.droog@gmail.com> - 2019-10-12 14:15 -0700
                  Re: A very small MVC prototype, for real this time... but need help... of course "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2019-10-12 23:53 +0200
    Re: A very small MVC prototype, for real this time... but need help... of course luserdroog <luser.droog@gmail.com> - 2019-10-05 23:38 -0700

#37500 — A very small MVC prototype, for real this time... but need help... of course

Fromluserdroog <luser.droog@gmail.com>
Date2019-10-04 21:43 -0700
SubjectA very small MVC prototype, for real this time... but need help... of course
Message-ID<476ce5c1-2d43-48cb-a935-3803c0195a1f@googlegroups.com>
Upon rereading the helpful suggestions from Michael Haufe, I noticed this
link which I had missed before,

  https://gist.github.com/mlhaufe/c841b2269b0099c3c52648717f9551cc

containing the very Model, View, and Controller classes in a short and
sweet, barebones implementation. I read through it, copied it by hand
into my notebook, and then retyped the handwritten copy to really get
a good sense of it all. So, I'd like to try to build up a very simple
usage example. 

Suppose for simplicity that the model is just represented by a simple 
integer and the only modifications are increment and decrement.

I want the page to display the current value and have clickable plus
and minus signs, buttons or divs or whatever.

In the following, incomplete solution, I instantiate a Model and specify
the member functions: setValue, inc, dec; all of which call this.notify()
after modifying the value.

The I instantiate a a View and set its model. And provide override the
default update function with a new function which queries the model and
modifies the DOM.

But I don't quite see how to stitch up the click handlers. And what do
I do with the Controller? Should my 'inc' and 'dec' functions go into
the controller object?


$ for f in eg.html app.js mvc.js; do echo ----- $f ------ ; cat $f ; done ;
----- eg.html ------
<!doctype html>
<html lang=en><meta charset=utf-8>
<script type=module src=app.js> </script>
<main>
  <div class=turtle >?</div>
  <div class=inc >+</div>
  <div class=dec >-</div>

----- app.js ------
let qs = (sel,ctx)=> (ctx || document).querySelector( sel );
import {Model, View, Controller} from './mvc.js';

let turtle = new Model();
turtle.setValue = function( value ){ this.value = value; this.notify() };
turtle.inc = function(){ ++this.value; this.notify() };
turtle.dec = function(){ --this.value; this.notify() };

let panel = new View();
panel.setModel( turtle );
panel.update = function(){
    qs('.turtle').innerHTML = this.getModel().value;
}

function main(){
  turtle.setValue( 0 );
}


document.addEventListener('DOMContentLoaded', main );
----- mvc.js ------
class Model {
  _observers = []
  observe( observer ){ this._observers.push( observer ) }
  unobserve(observer){ this._observers=this._observers.filter(o=> o!==observer)}
  notify( data ){ this._observers.forEach(o=> o.update(data) ) } }

class View {
  _subViews = []
  update(){}
  getModel(){ return this._model }
  setModel( model ){ this._setModelAndController( model, this._controller ) }
  getDefaultController(){ return new Controller }
  getController(){ if( !this._controller )
                     this.setController(this.getDefaultController())
                   return this._controller}
  setController(controller){this._setModelAndController(this._model,controller)}
  _setModelAndController( model, controller ){
    if( this._model !== model ){
      if( this._model ) this._model.unobserve( this )
      if( model ) model.observe( this )
      this._model = model
    }
    if( controller ){ controller.setView( this ); controller.setModel( model ) }
    this._controller = controller
  }
  getSubViews(){ return new Array( this._subViews ) }
  addSubView( subView ){
    var prev = subView.getSuperView()
    if( prev ) prev.removeSubView( subView )
    this._subViews.push( subView )
    subView.setSuperView( this )
  }
  removeSubView( subView ){
    this._subViews=this._subViews.filter(s=>{if(s===subView) s.setSuperView(null)
                                               return s !== subView })
  }
  setSuperView( superView ){ this._superView = superView }
  getSuperView(){ return this._superView }
  destroy(){
    if( this._model ) this._model.unobserve( this )
    this._subViews.forEach(s=> s.destroy() )
  } }

class Controller {
  getModel(){ return this._model }
  setModel( model ){ this._model = model }
  getView(){ return this._view }
  setView( view ){ this._view = view } }

export { Model, View, Controller }

[toc] | [next] | [standalone]


#37502

Fromluserdroog <luser.droog@gmail.com>
Date2019-10-05 12:52 -0700
Message-ID<0ab03e1a-bb5c-4294-b78f-ed6452e0ab0f@googlegroups.com>
In reply to#37500
On Friday, October 4, 2019 at 11:43:28 PM UTC-5, luserdroog wrote:

> let turtle = new Model();
> turtle.setValue = function( value ){ this.value = value; this.notify() };
> turtle.inc = function(){ ++this.value; this.notify() };
> turtle.dec = function(){ --this.value; this.notify() };

Small improvement. I can avoid repeating 'this.notify()' if all modifications
are routed through 'setValue()'.

let turtle = new Model();
turtle.setValue = function( value ){ this.value = value; this.notify() }
turtle.inc = function(){ this.setValue( this.value + 1 ) }
turtle.dec = function(){ this.setValue( this.value - 1 ) }

[toc] | [prev] | [next] | [standalone]


#37503

From"Evertjan." <exxjxw.hannivoort@inter.nl.net>
Date2019-10-05 22:52 +0200
Message-ID<XnsAADFE8B7FA177eejj99@194.109.6.166>
In reply to#37502
luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in 
comp.lang.javascript:

> turtle.inc = function(){ this.setValue( this.value + 1 ) }

why not skip the setValue definition and do:

turtle.inc = function(){ this.value = ++this.value;this.notify(); };

-- 
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

[toc] | [prev] | [next] | [standalone]


#37505

Fromluserdroog <luser.droog@gmail.com>
Date2019-10-05 23:26 -0700
Message-ID<c305cdfb-b07c-43ba-8488-b6305aefd83d@googlegroups.com>
In reply to#37503
On Saturday, October 5, 2019 at 3:53:18 PM UTC-5, Evertjan. wrote:
> luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in 
> comp.lang.javascript:
> 
> > turtle.inc = function(){ this.setValue( this.value + 1 ) }
> 
> why not skip the setValue definition and do:
> 
> turtle.inc = function(){ this.value = ++this.value;this.notify(); };
> 

It seems more DRY to call 'notify' in just one place. 

[toc] | [prev] | [next] | [standalone]


#37507

From"Evertjan." <exxjxw.hannivoort@inter.nl.net>
Date2019-10-06 11:39 +0200
Message-ID<XnsAAE07682CB95Beejj99@194.109.6.166>
In reply to#37505
luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
comp.lang.javascript:

> On Saturday, October 5, 2019 at 3:53:18 PM UTC-5, Evertjan. wrote:
>> luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in 
>> comp.lang.javascript:
>> 
>> > turtle.inc = function(){ this.setValue( this.value + 1 ) }
>> 
>> why not skip the setValue definition and do:
>> 
>> turtle.inc = function(){ this.value = ++this.value;this.notify(); };
>> 
> 
> It seems more DRY to call 'notify' in just one place. 

I more meant why tou needed a setValue function.

So:

turtle.inc = function(){ this.value = ++this.value; };

-- 
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

[toc] | [prev] | [next] | [standalone]


#37508

FromSilvio <silvio@internet.com>
Date2019-10-06 16:42 +0200
Message-ID<5d99fd5a$0$1711$e4fe514c@newszilla.xs4all.nl>
In reply to#37507
On 10/6/19 11:39 AM, Evertjan. wrote:
> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in
> comp.lang.javascript:
> 
>> On Saturday, October 5, 2019 at 3:53:18 PM UTC-5, Evertjan. wrote:
>>> luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in
>>> comp.lang.javascript:
>>>
>>>> turtle.inc = function(){ this.setValue( this.value + 1 ) }
>>>
>>> why not skip the setValue definition and do:
>>>
>>> turtle.inc = function(){ this.value = ++this.value;this.notify(); };
>>>
>>
>> It seems more DRY to call 'notify' in just one place.
> 
> I more meant why tou needed a setValue function.
> 
> So:
> 
> turtle.inc = function(){ this.value = ++this.value; };
> 

this.value = ++this.value ???

[toc] | [prev] | [next] | [standalone]


#37509

Fromluserdroog <luser.droog@gmail.com>
Date2019-10-06 11:22 -0700
Message-ID<ec21c9e0-f03f-4d7f-815d-c0c7baaf59ae@googlegroups.com>
In reply to#37507
On Sunday, October 6, 2019 at 4:39:06 AM UTC-5, Evertjan. wrote:
> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
> comp.lang.javascript:
> 
> > On Saturday, October 5, 2019 at 3:53:18 PM UTC-5, Evertjan. wrote:
> >> luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in 
> >> comp.lang.javascript:
> >> 
> >> > turtle.inc = function(){ this.setValue( this.value + 1 ) }
> >> 
> >> why not skip the setValue definition and do:
> >> 
> >> turtle.inc = function(){ this.value = ++this.value;this.notify(); };
> >> 
> > 
> > It seems more DRY to call 'notify' in just one place. 
> 
> I more meant why tou needed a setValue function.
> 
> So:
> 
> turtle.inc = function(){ this.value = ++this.value; };
> 

The Model needs to call 'notify' after any change to the value.
It seemed convenient to combine these into a single action.
I get the feeling that I'm not seeing the point you're trying
to make.

[toc] | [prev] | [next] | [standalone]


#37510

From"Evertjan." <exxjxw.hannivoort@inter.nl.net>
Date2019-10-06 22:25 +0200
Message-ID<XnsAAE0E42916C31eejj99@194.109.6.166>
In reply to#37509
luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
comp.lang.javascript:

> On Sunday, October 6, 2019 at 4:39:06 AM UTC-5, Evertjan. wrote:
>> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
>> comp.lang.javascript:
>> 
>> > On Saturday, October 5, 2019 at 3:53:18 PM UTC-5, Evertjan. wrote:
>> >> luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in 
>> >> comp.lang.javascript:
>> >> 
>> >> > turtle.inc = function(){ this.setValue( this.value + 1 ) }
>> >> 
>> >> why not skip the setValue definition and do:
>> >> 
>> >> turtle.inc = function(){ this.value = ++this.value;this.notify(); };
>> >> 
>> > 
>> > It seems more DRY to call 'notify' in just one place. 
>> 
>> I more meant why you needed a setValue function.
>> 
>> So:
>> 
>> turtle.inc = function(){ this.value = ++this.value; };
>> 
> 
> The Model needs to call 'notify' after any change to the value.
> It seemed convenient to combine these into a single action.
> I get the feeling that I'm not seeing the point you're trying
> to make.
> 

Repeat: why you need a setValue function???



-- 
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

[toc] | [prev] | [next] | [standalone]


#37511

FromJonas Thörnvall <jonas.thornvall@gmail.com>
Date2019-10-06 14:15 -0700
Message-ID<4234af8c-f975-486d-a5df-a146a48a6918@googlegroups.com>
In reply to#37510
Den söndag 6 oktober 2019 kl. 22:25:49 UTC+2 skrev Evertjan.:
> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
> comp.lang.javascript:
> 
> > On Sunday, October 6, 2019 at 4:39:06 AM UTC-5, Evertjan. wrote:
> >> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
> >> comp.lang.javascript:
> >> 
> >> > On Saturday, October 5, 2019 at 3:53:18 PM UTC-5, Evertjan. wrote:
> >> >> luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in 
> >> >> comp.lang.javascript:
> >> >> 
> >> >> > turtle.inc = function(){ this.setValue( this.value + 1 ) }
> >> >> 
> >> >> why not skip the setValue definition and do:
> >> >> 
> >> >> turtle.inc = function(){ this.value = ++this.value;this.notify(); };
> >> >> 
> >> > 
> >> > It seems more DRY to call 'notify' in just one place. 
> >> 
> >> I more meant why you needed a setValue function.
> >> 
> >> So:
> >> 
> >> turtle.inc = function(){ this.value = ++this.value; };
> >> 
> > 
> > The Model needs to call 'notify' after any change to the value.
> > It seemed convenient to combine these into a single action.
> > I get the feeling that I'm not seeing the point you're trying
> > to make.
> > 
> 
> Repeat: why you need a setValue function???
> 
> 
> 
> -- 
> Evertjan.
> The Netherlands.
> (Please change the x'es to dots in my emailaddress)

To not have a static model, isn't setValue part of the user interface "guessing wildly"

[toc] | [prev] | [next] | [standalone]


#37512

Fromluserdroog <luser.droog@gmail.com>
Date2019-10-06 14:25 -0700
Message-ID<3be9b304-8c70-41fb-aa81-1858c1bb145a@googlegroups.com>
In reply to#37510
On Sunday, October 6, 2019 at 3:25:49 PM UTC-5, Evertjan. wrote:
> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
> comp.lang.javascript:
> 
> > On Sunday, October 6, 2019 at 4:39:06 AM UTC-5, Evertjan. wrote:
> >> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
> >> comp.lang.javascript:
> >> 
> >> > On Saturday, October 5, 2019 at 3:53:18 PM UTC-5, Evertjan. wrote:
> >> >> luserdroog <luser.droog@gmail.com> wrote on 05 Oct 2019 in 
> >> >> comp.lang.javascript:
> >> >> 
> >> >> > turtle.inc = function(){ this.setValue( this.value + 1 ) }
> >> >> 
> >> >> why not skip the setValue definition and do:
> >> >> 
> >> >> turtle.inc = function(){ this.value = ++this.value;this.notify(); };
> >> >> 
> >> > 
> >> > It seems more DRY to call 'notify' in just one place. 
> >> 
> >> I more meant why you needed a setValue function.
> >> 
> >> So:
> >> 
> >> turtle.inc = function(){ this.value = ++this.value; };
> >> 
> > 
> > The Model needs to call 'notify' after any change to the value.
> > It seemed convenient to combine these into a single action.
> > I get the feeling that I'm not seeing the point you're trying
> > to make.
> > 
> 
> Repeat: why you need a setValue function???
> 
> 

To combine two actions which should always be performed together:
storing the new value and notifying observers that a new value
has been stored. 

In my current playpen, I've moved it into the Model class so I don't
have to repeat it in each model.

[toc] | [prev] | [next] | [standalone]


#37532

Fromluserdroog <luser.droog@gmail.com>
Date2019-10-12 14:15 -0700
Message-ID<4f2e5a14-ac85-46ff-b30d-4a33d6f71120@googlegroups.com>
In reply to#37510
On Sunday, October 6, 2019 at 3:25:49 PM UTC-5, Evertjan. wrote:
> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
> comp.lang.javascript:
> 
> > 
> > The Model needs to call 'notify' after any change to the value.
> > It seemed convenient to combine these into a single action.
> > I get the feeling that I'm not seeing the point you're trying
> > to make.
> > 
> 
> Repeat: why you need a setValue function???
> 

Since this exchange, I've learned about getters and setters. Is that
what you were suggesting? To hook my function on property access with
a setter?

[toc] | [prev] | [next] | [standalone]


#37533

From"Evertjan." <exxjxw.hannivoort@inter.nl.net>
Date2019-10-12 23:53 +0200
Message-ID<XnsAAE6F30983C45eejj99@194.109.6.166>
In reply to#37532
luserdroog <luser.droog@gmail.com> wrote on 12 Oct 2019 in 
comp.lang.javascript:

> On Sunday, October 6, 2019 at 3:25:49 PM UTC-5, Evertjan. wrote:
>> luserdroog <luser.droog@gmail.com> wrote on 06 Oct 2019 in 
>> comp.lang.javascript:
>> 
>> > 
>> > The Model needs to call 'notify' after any change to the value.
>> > It seemed convenient to combine these into a single action.
>> > I get the feeling that I'm not seeing the point you're trying
>> > to make.
>> > 
>> 
>> Repeat: why you need a setValue function???
>> 
> 
> Since this exchange, I've learned about getters and setters. Is that
> what you were suggesting? To hook my function on property access with
> a setter?

I am not suggesting you learned something
I'm not suggesting anything, I am just asking.

"To hook my function on property access" 
What does "to hook A on B" mean?
Why would you need that?

-- 
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

[toc] | [prev] | [next] | [standalone]


#37506

Fromluserdroog <luser.droog@gmail.com>
Date2019-10-05 23:38 -0700
Message-ID<c63e99c9-07bb-498e-b568-1f730aa89bd8@googlegroups.com>
In reply to#37500
On Friday, October 4, 2019 at 11:43:28 PM UTC-5, luserdroog wrote:
> Upon rereading the helpful suggestions from Michael Haufe, I noticed this
> link which I had missed before,
> 
>   https://gist.github.com/mlhaufe/c841b2269b0099c3c52648717f9551cc
> 
> containing the very Model, View, and Controller classes in a short and
> sweet, barebones implementation. I read through it, copied it by hand
> into my notebook, and then retyped the handwritten copy to really get
> a good sense of it all. So, I'd like to try to build up a very simple
> usage example. 
> 
> Suppose for simplicity that the model is just represented by a simple 
> integer and the only modifications are increment and decrement.
> 
> I want the page to display the current value and have clickable plus
> and minus signs, buttons or divs or whatever.
> 
[snip]

I think I have it worked out a little better. The model has the function
'setValue' which calls the Model class's 'notify' function.

The view modifies the DOM in response to an 'update' from the model.

The controller has functions named to match DOM element classes and
a single click handler function routes all click events to their 
respective controller functions.

> 
> $ for f in eg.html app.js mvc.js; do echo ----- $f ------ ; cat $f ; done ;
> ----- eg.html ------

<!doctype html>
<html lang=en><meta charset=utf-8>
<script type=module src=app.js> </script>
<main>
  <div class=turtle >?</div>
  <div class=plus   >+</div>
  <div class=minus  >-</div>

> ----- app.js ------

let qs = (sel,ctx)=> (ctx || document).querySelector( sel );
import {Model, View, Controller} from './mvc.js';

function main(){
  turtle.setValue( 0 );
}


var turtle = new Model();
turtle.setValue = function( value ){ this.value = value; this.notify() };
turtle.inc = function(){ this.setValue( this.value + 1 ) };
turtle.dec = function(){ this.setValue( this.value - 1 ) };

var panel = new View();
panel.setModel( turtle );
panel.update = function(){ qs('.turtle').innerHTML = this.getModel().value; }

var control = panel.getController();
control.plus  = function(){ this.getModel().inc() }
control.minus = function(){ this.getModel().dec() }


function click( e ){
  if( typeof( control[ e.target.className ] ) == 'function' )
    control[ e.target.className ]()
}

document.addEventListener('DOMContentLoaded', main );
document.addEventListener('click', click );



> ----- mvc.js ------
> class Model {
>   _observers = []
>   observe( observer ){ this._observers.push( observer ) }
>   unobserve(observer){ this._observers=this._observers.filter(o=> o!==observer)}
>   notify( data ){ this._observers.forEach(o=> o.update(data) ) } }
> 
> class View {
>   _subViews = []
>   update(){}
>   getModel(){ return this._model }
>   setModel( model ){ this._setModelAndController( model, this._controller ) }
>   getDefaultController(){ return new Controller }
>   getController(){ if( !this._controller )
>                      this.setController(this.getDefaultController())
>                    return this._controller}
>   setController(controller){this._setModelAndController(this._model,controller)}
>   _setModelAndController( model, controller ){
>     if( this._model !== model ){
>       if( this._model ) this._model.unobserve( this )
>       if( model ) model.observe( this )
>       this._model = model
>     }
>     if( controller ){ controller.setView( this ); controller.setModel( model ) }
>     this._controller = controller
>   }
>   getSubViews(){ return new Array( this._subViews ) }
>   addSubView( subView ){
>     var prev = subView.getSuperView()
>     if( prev ) prev.removeSubView( subView )
>     this._subViews.push( subView )
>     subView.setSuperView( this )
>   }
>   removeSubView( subView ){
>     this._subViews=this._subViews.filter(s=>{if(s===subView) s.setSuperView(null)
>                                                return s !== subView })
>   }
>   setSuperView( superView ){ this._superView = superView }
>   getSuperView(){ return this._superView }
>   destroy(){
>     if( this._model ) this._model.unobserve( this )
>     this._subViews.forEach(s=> s.destroy() )
>   } }
> 
> class Controller {
>   getModel(){ return this._model }
>   setModel( model ){ this._model = model }
>   getView(){ return this._view }
>   setView( view ){ this._view = view } }
> 
> export { Model, View, Controller }

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web