Skip to content

Instantly share code, notes, and snippets.

@gintares
Created November 8, 2016 01:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gintares/d7f962137778d0950f1e88ccb47392d0 to your computer and use it in GitHub Desktop.
Save gintares/d7f962137778d0950f1e88ccb47392d0 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<!--
https://jsfiddle.net/b9baaw70/7/ - 2016-11-06
https://jsfiddle.net/b9baaw70/10/ - 2016-11-07
http://localhost/leaJQ/articles/articleBind1a.html
C:\Bitnami\wampstack-5.6.20-0\apache2\htdocs\leaJQ\articles\articleBind1.html
C:\Bitnami\wampstack-5.6.20-0\apache2\htdocs\leaJQ\typing_and_others\functionalities_w\articleBind1.html
C:\Bitnami\wampstack-5.6.20-0\apache2\htdocs\leaJQ\articles\articleBind1a.html
//Embed code
<script async src="//jsfiddle.net/b9baaw70/embed/js,html,result/"></script>
-->
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
p {
text-align : justify;
}
</style>
</head>
<body>
<h2> Composite objects from the same bricks, nevertheless, having different functions </h2>
<p> Example of creation of composite objects from bricks, i.e. objects having only string/integer/array/object valued properties ( having no methods-functions),
and implementing `bind` or prototype to functionalise these composite object.
<br> It should be applied to objects, which have different functionalities although consist of the same bricks.</p>
<h2>
MAIN IDEA
</h2> <p> Create brick-objects having only properties with string, number and array/object values.
<br> Such brick-objects can be easy copied, added and substracted using JSON.parse(JSON.stringify(obj)) fast, because they do not have methods.
<br> ( I do not show here how to add or substract two JSON objects in order to get a third object. )
<br> The HTML form example visualizes the idea:
<br> * steps 1&2) the bricks (for example HTML5 elements) compose the object (for example HTML5 form),
<br> * step3) `bind`, attaches different functionalities,
<br> * step5) simple helping function creates composite object copies.
<br> * step6) it is possible to use prototype instead of `bind`.
<br><br><br>See explanations in the code. Click or write in input to log the type of the event and id. </p>
<br> <div id="form1" > </div>
<br> <div id="form3" > </div>
<br> <div id="form4" > </div>
<br> <div id="form5" > </div>
<h2>
CONCLUSION
</h2> <p> Create composite objects from objects having only properties,
and functionalise them either through prototype or using `bind`. </p>
<script>
/*
The MIT License (MIT)
Copyright (c) <2016-11-05> <copyright holder : Gintare Statkute, g.statkute@gmail.com > Copyright (c) <2016-11-05> <copyright holder : Gintare Statkute, g.statkute@gmail.com > <version 1.3>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice with name of copyright holder and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
window.onload = function() {
/* example how to iterate
var obj1 ={ 'inputName' : {'name':'input', 'label':'(form1) Name:'} ,
'inputPasswd' : {'name':'input', 'label':'(form1) Password:'} };
for (item of Object.entries(obj1) ) { console.log(item) }; //obj1[Symbol.iterator] is not a function(…)
for (key of Object.keys(obj1) ) { console.log(key) }; //obj1[Symbol.iterator] is not a function(…)
*/
// HELPING FUNCTIONS
// Angus Croll //array, object, function
//https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
function whatTypeFnc(obj) { return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase() } ;
var copyComp = function ( form1 ){
var form2 = ( JSON.parse(JSON.stringify(form1)) );
for ( prop of Object.getOwnPropertyNames(form1) ) {
console.log(form1[prop]);
form2[prop] = form1[prop];
}
return form2;
}
// EXAMPLE
// ************************************************************
// Step1. brick object - HTML5 element
//could also be set, because every key is unique
var elemHTML5 = { elemtype:'elemHTML5' , name : 'input', label :'', value:'', id: '', bchecked:null, bhidden:null, title:'', style: { width : '10px'} } ;
// functions dealing with COmposite objects constructed from elemHTML
function setComp1( key, keyElem, value ) { this[key][keyElem] = value;};
//{ 'inputName' : {'name':'input', 'label':'(form1) Name:'} , 'inputPasswd' : {'name':'input', 'label':'(form1) Password:'} };
// function setCompM( obj ) { Object.assign(this, obj); } deletes not assigned values. I need to overwrite the give, and leave already existing
function setCompMany1( obj ) {
console.log(Object.keys(obj));
for ( prop of Object.keys(obj) ) {
if ( this[prop]) {
console.log( 'prop exists : '+prop);
for ( item of Object.keys(obj[prop]) ) {
console.log( ' seting item : '+ item)
if(!item instanceof Object ) { setCompMany1.call(this[prop], obj[prop][item] )}
else { this[prop][item] = obj[prop][item]; }
} } } };
function getComp(key) { return this[key]; };
function addComp(prop) { /* add property to elemHTML5 like, style.height, */ }
function removeComp(prop) { /* add property to elemHTML5 like, title, */ }
function assignEvents( eventsArr, formid ) {
var eventTypes = ['click', 'input','keydown','keyup','mousedown','mouseup','focus'] ; //add more
//formid=this.__proto__.name;
for( type of eventsArr){
if( eventTypes.indexOf(type) >=0 ) {
//chek if event type is right ....
//document.getElementById( 'form1' ).addEventListener("mousedown", form1, false);
console.log( " assigning "+type+" to form "+formid );
document.getElementById(formid).addEventListener(type, this, false);
} } };
function initComp1(formid, eventsArr) {
this.__proto__.name = formid || Math.floor(Math.random()*1000); //it will be form id
assignEvents.call(this, eventsArr, formid);
for ( property of Object.getOwnPropertyNames(this) ) {
// property == elemHTML5, property === elemHTML5, Right-hand side of 'instanceof' is not callable(…)
// console.log( " property = " + property );
if (this[property].elemtype) {
if(this[property].elemtype === 'elemHTML5' ) {
this[property].id = Math.floor(Math.random()*1000);
console.log( ' this['+property+'].id = ' + this[property].id );
} } } };
// function initComp2()
function displayComp1() {
var output="";
// console.log('************** displayComp 0 level'); console.log( Object.getOwnPropertyNames(this) );
for ( property of Object.getOwnPropertyNames(this) ) {
// set, get and display are strings, not functions
if( whatTypeFnc(property) !== 'function') {
// console.log('*** displayComp 1 level'); console.log(property);
// console.log( whatTypeFnc(property) );
// console.log( Object.keys(this[property] ) );
// set, get and display are strings, not functions, thus you have to check if they are arrays
if( Object.keys(this[property]).length > 0 ) {
output+= "<div>"+ this[property].label + ": <" + this[property].name +' id="'+ this[property].id+'"';
if(this[property].bchecked) { output+= this[property].bchecked; }
output+= ">" + this[property].value + "</" + this[property].name + "></div>" ;
} console.log(output);
} }
formid=this.__proto__.name;
document.getElementById(formid).innerHTML = output;
//return output;
} ;
displayComp2 = function() { } //another way to display the form
eventHandler1 = function(event) {
console.log( 'tagName = '+event.target.tagName+', Id = '+event.target.id+', type='+event.type );
var formid = this.__proto__.name;
var div = document.createElement('div');
div.id = 'cons'+Math.floor(Math.random()*1000);
div.innerHTML = 'tagName = '+event.target.tagName+', Id = '+event.target.id+', type='+event.type;
document.getElementById(formid).appendChild(div);
// a lot of code for different kind of events
}
eventHandler2 = function(event) {} // different way of handking various events
// here can be also methods enabling to set many keys, and keyElem4 values simultaneously,
// and other methods, dealing with validation , ajax, database
// also initialization method, dealing wuth default values, proerties and id creation at the moment of composite object creation
// ************************************************************
// Step2. Composite object - form constructor
var LoginFormFnc = function() {
this.inputName = ( JSON.parse(JSON.stringify(elemHTML5)) );
this.inputPasswd = ( JSON.parse(JSON.stringify(elemHTML5)) );
};
// Step3. bind attach functionality
var form1 = new LoginFormFnc();
form1.init = initComp1.bind(form1);
form1.set = setComp1.bind(form1); // it is a string, not a function if you check using whatTypeFnc ( Object.getOwnPropertyNames(this) )
form1.setM = setCompMany1.bind(form1);
form1.display = displayComp1.bind( form1 ); //you can select the display method you want
form1.handleEvent = eventHandler1.bind( form1 ); // object can have one handleEvent method, but you can choose which functionality you want by assigning proper handler : handler1 or handler2, ...
//form1.assignEvent = assignEvent.call(form1, ['click', 'keyup', 'keydown', 'change','mousedown','mouseup', 'input']);
// does not work : form1.prototype.set
// Step4. Implement the form - initialize (set id, and attach events), set properties, display....
console.log( " *********************************** init form 1");
form1.init('form1', ['click', 'keyup', 'keydown', 'change','mousedown','mouseup', 'input'] );
console.log(form1);
console.log( " *********************************** Setting form 1");
form1.setM( { 'inputName' : {'name':'input', 'label':'(form1) Name:'} ,
'inputPasswd' : {'name':'input', 'label':'(form1) Password:'} } );
console.log(form1);
form1.display(); //document.getElementById('form1').innerHTML = form1.display();
// ************************************************************
// Step5. copy the created for to another form
/* logs before c opying
console.log('form2');
console.log('Object.getOwnPropertyNames(form1) '); console.log( Object.getOwnPropertyNames(form1) );
console.log( Object.getOwnPropertyNames(form2) );
console.log(' Object.keys(form1)' );console.log( Object.keys(form1) );
console.log( Object.keys(form2) ); */
console.log(' COPYING ***************************************** ');
var form3 = copyComp(form1);
form3.init('form3', ['click', 'keyup', 'keydown', 'change','mousedown','mouseup', 'input'] );
//Set labels
form3.setM( { 'inputName' : {'name':'input', 'label':'(form3) Name:'} ,
'inputPasswd' : {'name':'input', 'label':'(form3) Password:'} } );*/
form3.display();
console.log(form3);
// ************************************************************
// Step 6. Example that it is possible to achieve this using prototype (instead of bind). If one utilize prototype, no need for copying!
var LoginFormProtFnc = function(formid, eventsArr) {
this.inputName = ( JSON.parse(JSON.stringify(elemHTML5)) );
this.inputPasswd = ( JSON.parse(JSON.stringify(elemHTML5)) );
var objId = formid || Math.floor(Math.random()*1000); // will contain the id of form, does not work from init()
this.getObjId = function() { return objId; }
this.setObjId = function(objId) { objId = objId; }
this.init(objId, eventsArr);
this.display(); //prints empty divs, maybe because Object.keys() and values are not know to this point??
};
LoginFormProtFnc.prototype.set = function( key, keyElem, value ){ this[key][keyElem] = value;};
//{ 'inputName' : {'name':'input', 'label':'(form1) Name:'} , 'inputPasswd' : {'name':'input', 'label':'(form1) Password:'} };
// function setCompM( obj ) { Object.assign(this, obj); } deletes not assigned values. I need to overwrite the give, and leave already existing
LoginFormProtFnc.prototype.setM = function ( obj ) {
console.log(Object.keys(obj));
for ( prop of Object.keys(obj) ) {
if ( this[prop]) {
// console.log( 'prop exists : '+prop);
for ( item of Object.keys(obj[prop]) ) {
// console.log( ' seting item : '+ item)
if(!item instanceof Object ) { setCompMany1.call(this[prop], obj[prop][item] )}
else { this[prop][item] = obj[prop][item]; }
} } } };
LoginFormProtFnc.prototype.init = function (formid, eventsArr) {
//assignEvents is the same as above
assignEvents.call(this, eventsArr, formid);
for ( property of Object.getOwnPropertyNames(this) ) {
if (this[property].elemtype) {
if(this[property].elemtype === 'elemHTML5' ) {
this[property].id = Math.floor(Math.random()*1000);
// console.log( ' this['+property+'].id = ' + this[property].id );
} } } };
//LoginFormProtFnc.prototype.getLoginForm = function(key) { return this[key]; };*/
LoginFormProtFnc.prototype.display = function() {
var output="";
// console.log( Object.keys(this) ); // ["inputName", "inputPasswd", "init", "getObjId", "setObjId"]
// console.log( Object.getOwnPropertyNames(this) ); // ["inputName", "inputPasswd", "init", "getObjId", "setObjId"]
for ( property of Object.keys(this) ) {
//console.log( Object.keys(this[property] ) + ' is '+ whatTypeFnc(Object.keys(this[property] )) );
//logs that functions from Object.keys(this[property]) are empty arrays, thus you check the length to get only HTML5 properties
//if( Object.keys(this[property]).length > 0 ) {
if (this[property].elemtype) {
if(this[property].elemtype === 'elemHTML5' ) {
output+= "<div>"+ this[property].label + ": <" + this[property].name+' id="'+ this[property].id+'"';
if(this[property].bchecked) { output+= this[property].bchecked; }
output+= ">" + this[property].value + "</" + this[property].name + "></div>" ;
console.log(output);
} } } document.getElementById( this.getObjId() ).innerHTML = output; };
// return output; } ;
//Each composite object, would have own handler
LoginFormProtFnc.prototype.handleEvent= function(event) {
console.log(' tagName = '+event.target.tagName+', Id = '+event.target.id+', type='+event.type);
var div = document.createElement('div');
div.id = 'cons'+Math.floor(Math.random()*1000);
div.innerHTML = 'tagName = '+event.target.tagName+', Id = '+event.target.id+', type='+event.type;
document.getElementById( this.getObjId() ).appendChild(div);
// practically the handler comprise several functions dealing with eventType for ObjectType
// for instance, calendar object, would have events dealing with user click on day
// most of form objects, would have keyup(input) and mousedown(choice) event
// shape objects would have drag, scale, resize, etc ... events
}
// here can be also methods enabling to set many keys, and keyElem4 values simultaneously,
// and other methods, dealing with validation , ajax, database
// also initialization method, dealing wuth default values, proerties and id creation at the moment of composite object creation
//displays form
var form4 = new LoginFormProtFnc('form4', ['click', 'keyup', 'keydown', 'change','mousedown','mouseup', 'input'] );
console.log(form4);
// sets labels to form fields:
form4.setM( { 'inputName' : {'name':'input', 'label':'(form4) Name:'} , 'inputPasswd' : {'name':'input', 'label':'(form4) Password:'} } );
console.log(form4);
form4.display();
//var form5 = assignProtObj(form4); // to be implemented, involved deep copy of the object.
};
</script>
</body>
</html>
@gintares
Copy link
Author

gintares commented Nov 8, 2016

Improoved form. Example how javascript object, could be created from simple compounds, functionalised, copied, etc...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment