Code Monkey home page Code Monkey logo

backbone-nested's People

Contributors

afeld avatar bartek avatar eddieantonio avatar fcamblor avatar gkatsev avatar isakb avatar karlwestin avatar lovetheidea avatar michaelcox avatar p3drosola avatar trevorquinn avatar yepitschunked avatar zincli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

backbone-nested's Issues

easy adding to nested arrays

Would be nice to be able to add items to nested arrays, without having to know destination index. Possible syntax:

user.set({
  'addresses[]': {
    city: 'Seattle',
    state: 'WA'
  }
});

Uncaught TypeError: Object function (){e.apply(this,arguments)} has no method 'walkPath'

If i create a NestedModel within my models.js, anytime I attempt to update the model through code, I receive the above error. My model is instantiated like so:

var Special = Backbone.NestedModel.extend({
    initialize : function () {
        // Log the changed properties
        this.on('change', function (model, options) {
            for ( var i in options.changes)
                this.display();
            updateSession(model);
        });
        // Update session var
        this.updateSession(this);
    },
    //Attributes
    defaults : function () {
        return {
            "Product" : null,
            "ShortDescription" : null,
            "Category" : "food",
            "Price" : {
                "Regular" : null,
                "Special" : null,
                "PercentOff" : null
            },
            "Date" : {
                "StartTime" : null,
                "EndTime" : null,
                "HumanTimeRange" : null
            },
            "Uses" : 0,
            "Tags" : [],
            "Contributor" : null
        }
    },

    //Functions
    display : function (property) {
        console.log(property + ': ' + this.get(property));
    },
    displayAll : function () {
        console.log('Product: ' + this.get('Product'));
        console.log('ShortDescription: ' + this.get('ShortDescription'));
        console.log('Category: ' + this.get('Category'));
        console.log('Price: {');
        console.log('  Regular: ' + this.get('Price.Regular'));
        console.log('  Special: ' + this.get('Price.Special'));
        console.log('  PercentOff: ' + this.get('Price.PercentOff') + '\n}');
        console.log('Date: {');
        console.log('  StartTime: ' + this.get('Date.StartTime'));
        console.log('  EndTime: ' + this.get('Date.EndTime'));
        console.log('  HumanTimeRange: ' + this.get('Date.HumanTimeRange') + '\n}');
        console.log('Uses: ' + this.get('Uses'));
        console.log('Tags: ' + this.get('Tags'));
        console.log('Contributor: ' + this.get('Contributor'));
    },
    updateSession : function (model) {
        Session.set('NewSpecial', model);
    }
});

// Empty special to hold user entered data pertaining to new special creation
NewSpecial = new Special();

If i attempt to modify the contents with NewSpecial.set('Category', 'travel') I get the error. If i copy the same exact code but instantiate the model in the console, everything works fine. I'm using the backbone-nested.js as a smart package in Meteor (I packaged it myself and will upload it to Atmosphere for community use shortly).

Escape Method Not Implemented

From Backbone Docs:

escapemodel.escape(attribute)
Similar to get, but returns the HTML-escaped version of a model's attribute. If you're interpolating data from the model into HTML, using escape to retrieve attributes will prevent XSS attacks.

check for window before calling window.console

If you are trying to use this library in node.js there is not a global window. I fixed the error by simply adding:

if(typeof window === 'undefined')var window = {};

above the code and under my custom AMD wrapper. But I'm sure there is a standard or better way of making this work in node.js.

Cannot read property 0 of undefined

This is an extension of the issue I already opened, #70. If I copy the Backbone.NestedModel.extend({...}) in the linked issue, and paste it after
var other = (pasted code), a new model object is created with no issues. If i do

>other.set({'Date.StartTime': 'never'})

I get:

  TypeError: Cannot read property '0' of undefined
  arguments: Array[2]
    0: 0
    1: undefined
    length: 2
    __proto__: Array[0]
get message: function () { [native code] }
get stack: function () { [native code] }
set message: function () { [native code] }
set stack: function () { [native code] }
type: "non_object_property_load"
__proto__: Error

If i do the same exact >other.set({'Date.StartTime': 'never'}) command immediately after, it works fine. This is obviously creating issues where I set attributes in code where I don't have the option to run the block again.

having issues getting this to work with meteor...

I import jQuery, underscore, and backbone as smart packages in meteor. I have a
<script src="/javascripts/backbone-nested.js"></script>
import in my head.html file, but when my models are loaded i get a "cannot call method 'extend' of undefined" error

Improve set performance (IE8)

It seems that set is very slow operation in IE8 this leads to poor performance for example if you need to iterate over collection of models and set bunch of attributes. Consider ways to improve it's performance.

changedAttributes() is not consistent when setting using nested string syntax vs. passing full JSON object

When calling model.set using the Backbone-Nested string syntax (method A), model.changedAttributes() returns a complete list, including both the nested JSON and the nested string syntax of changes:

name: {
  first: 'Aidan',
  middle: {
    initial: 'L',
    full: 'Limburger'
  },
  last: 'Feldman'
},
'name.middle': {
  initial: 'L',
  full: 'Limburger'
},
'name.middle.full': 'Limburger'

When calling model.set using a JSON object like so (method B)...

doc.set({
  gender: 'M',
  name: {
    first: 'Aidan',
    middle: {
      initial: 'L',
      full: 'Limburger'
    },
    last: 'Feldman'
  },
  addresses: [
    {
      city: 'Brooklyn',
      state: 'NY'
    },
    {
      city: 'Oak Park',
      state: 'IL'
    }
  ]
});

... changedAttributes() only returns the top level changed attribute, not the nested string hash:

name: {
  first: 'Aidan',
  middle: {
    initial: 'L',
    full: 'Limburger'
  },
  last: 'Feldman'
}

This might not seem like a big deal, but some of the set operations, for example like the one I believe happens as a result of model.fetch, are not developer-controlled and use method B. This creates problems for code that needs the nested strings in changedAttributes (like Backbone.ModelBinder). It's also a consistency issue.

A test demonstrating this is available on my fork: https://github.com/trevorquinn/backbone-nested/blob/master/test/nested-model.js

Use Sinon to Better Assert Triggers

Hey Aidan,

I was thinking it'd be nice if we could assert the triggers a bit better. One of the things I'd like to confirm is that each trigger is only being fired once, and that they're being sent in the correct order (which I would say is bottom-up). To do that, I'm thinking of importing Sinon to the test suite so that we can do some additional checking.

So instead of this:

  test("change event on deeply nested attribute", function() {
    var callbacksFired = [false, false, false, false];

    doc.bind('change', function(){ callbacksFired[0] = true; });
    doc.bind('change:name', function(){ callbacksFired[1] = true; });
    doc.bind('change:name.middle', function(){ callbacksFired[2] = true; });
    doc.bind('change:name.middle.full', function(){ callbacksFired[3] = true; });

    doc.bind('change:name.middle.initial', function(){ ok(false, "'change:name.middle.initial' should not fire"); });
    doc.bind('change:name.first', function(){ ok(false, "'change:name.first' should not fire"); });

    doc.set({'name.middle.full': 'Leonard'});

    ok(callbacksFired[0], "'change' should fire");
    ok(callbacksFired[1], "'change:name' should fire");
    ok(callbacksFired[2], "'change:name.middle' should fire");
    ok(callbacksFired[3], "'change:name.middle.full' should fire");
  });

Doing something like this:

  test("change event on deeply nested attribute", function() {
    var change = sinon.spy();
    var changeName = sinon.spy();
    var changeNameMiddle = sinon.spy();
    var changeNameMiddleFull = sinon.spy();
    var changeNameMiddleInitial = sinon.spy();
    var changeNameFirst = sinon.spy();

    doc.bind('change', change);
    doc.bind('change:name', changeName);
    doc.bind('change:name.middle', changeNameMiddle);
    doc.bind('change:name.middle.full', changeNameMiddleFull);

    doc.bind('change:name.middle.initial', changeNameMiddleInitial);
    doc.bind('change:name.first', changeNameFirst);

    doc.set({'name.middle.full': 'Leonard'});

    ok(change.calledOnce);
    ok(change.calledAfter(changeName));

    ok(changeName.calledOnce);
    ok(changeName.calledAfter(changeNameMiddle));

    ok(changeNameMiddle.calledOnce);
    ok(changeNameMiddle.calledAfter(changeNameMiddleFull));

    ok(changeNameMiddleFull.calledOnce);

  });

Thoughts?

change event options parameter not detailed enough

The change event handler is passed the model and an options object that contains the attributes that have changed. Because you're calling the super's set(), its just specifying the top level attribute that changed. Ideally, this would specify the actual attributes that changed, similar to Backbone.DeepModel. Basically, there's a loss of information with what actually changed, and binding to the all event to get the change:* events has the problem that its not possible to dedupe changes.

Using model.changedAttributes() doesn't handle this use case because it accumulates all changes to the model

The use case I'm trying to support to syncing a model to a plain old javascript object for use with JsViews, and I would like to do this as efficiently as possible.

I'm guessing this isn't something you'd be able to support, but it would be nice.

_delayedTriggers is a singleton, but should be private per model instance

The _delayedTriggers storage is a singleton (shared across all instances). As a result, if during instance A event dispatch an event listener performs some action resulting in events being triggered on a different instance (instance B), instance B will drain the remaining delayed triggers from instance A. Thus, events can trigger on the wrong instance :(

Add AMD support

This helps when using requirejs and the included optimizer or you get always the message that Backbone can not be found.

Should change event trigger before data is set on the model?

When a change event fires on a nested property, should a listener be able to access the new value of that property on the model during the change event by doing a model.get(...)?

For example:

//shortened representation of model
model = {
  arr: [
       {
           country: "GB"
       }
  ]
}
//Set nested property
model.set("arr[0].country", "IE");
//change event listener for nested property
model.on("change:arr[0].country", function( model, value, options ) {
    //value is correct
    //value = IE
    //model value still has old value
    //model.get("arr[0].country") = GB
});

On a top level property, the model.get(...) also gets the same result as value.

Nested sets that fail validation still trigger change events and are added to changedAttributes

Set operations on nested model attributes that fail validation are triggering change events in backbone-nested, and I don't think that's how it's intended to work in Backbone. If you try invalid set operations on regular attributes, they do not trigger change events, and I think it should be the same for nested attributes.

Also, it looks like invalid sets on nested attributes are updating the changedAttributes for the model and these are not cleared out when future change events are fired. This is affecting integration with other libraries like Backbone.ModelBinding.

I think there is something that runs in model sets before the this.changed is altered (in the normal Backbone Model class), which Backbone-Nested, in handling nested properties, does not do:

if (!this._validate(attrs, options)) return false;

The unit test below should demonstrate this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta name="generator" content="HTML Tidy for Windows (vers 14 February 2006), see www.w3.org">
        <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
        <link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen">
        <script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script>
        <script type="text/javascript" src="http://underscorejs.org/underscore.js"></script>
        <script type="text/javascript" src="http://documentcloud.github.com/backbone/backbone.js"></script>
        <script type="text/javascript" src="https://raw.github.com/afeld/backbone-nested/master/backbone-nested.js"></script>

 <script type="text/javascript">
$(document).ready(function(){


    module("Backbone-Nested testing", {

        setup: function() {

            // Top level parent model with nested stuff
            this.ParentBBModel = Backbone.NestedModel.extend({
                validate : function(attributes) {
                    if (attributes.firstLevelChild.firstLevelChildAttrA.length < 25) {
                        return "firstLevelChild.firstLevelChildAttrA must be at least 25 characters";
                    } else if (attributes.parentAttrA.length < 16) {
                        return "parentAttrA must be at least 16 characters";
                    }
                }
            });
            this.parentBBModel = new this.ParentBBModel({
                parentAttrA : "parentAttrAValue",
                firstLevelChild : {
                    firstLevelChildAttrA : "firstLevelChildAttrAValue",
                    firstLevelChildAttrB : "firstLevelChildAttrBValue",
                    secondLevelArray : [
                        {
                            secondLevelArrObjAttrA : "secondLevelArrObj0AttrAValue",
                            secondLevelArrObjAttrB : "secondLevelArrObj0AttrBValue"
                        },
                        {
                            secondLevelArrObjAttrA : "secondLevelArrObj1AttrAValue",
                            secondLevelArrObjAttrB : "secondLevelArrObj1AttrBValue"
                        },
                        {
                            secondLevelArrObjAttrA : "secondLevelArrObj2AttrAValue",
                            secondLevelArrObjAttrB : "secondLevelArrObj2AttrBValue"
                        }
                    ]
                },
                firstLevelArray : [
                    {
                        firstLevelArrObjAttrA : "firstLevelArrObj0AttrAValue",
                        firstLevelArrObjAttrB : "firstLevelArrObj0AttrBValue"
                    },
                    {
                        firstLevelArrObjAttrA : "firstLevelArrObj1AttrAValue",
                        firstLevelArrObjAttrB : "firstLevelArrObj1AttrBValue"
                    },
                    {
                        firstLevelArrObjAttrA : "firstLevelArrObj2AttrAValue",
                        firstLevelArrObjAttrB : "firstLevelArrObj2AttrBValue"
                    }
                ]
            });
        },

        teardown: function() {

        }

    });

    test("change should not be triggered for invalid updates to regular attributes", function() {
        var changeCallbackCalled = false;

        this.parentBBModel.bind('change:parentAttrA', function(model, errors) {
            changeCallbackCalled = true; 
        });

        // Change a nested attribute to invalid value
        this.parentBBModel.set({"parentAttrA" : "tooShort"});   

        // Verify there was no change made
        equal( this.parentBBModel.get("parentAttrA"), "parentAttrAValue");

        // The change event should not be triggered because the attribute was never changed (it failed validation)
        ok(!(changeCallbackCalled));
    });

    test("change should not be triggered for invalid updates to nested attributes", function() {
        var changeCallbackCalled = false;

        this.parentBBModel.bind('change:firstLevelChild.firstLevelChildAttrA', function(model, errors) {
            changeCallbackCalled = true; 
        });

        // Change a nested attribute to invalid value
        this.parentBBModel.set({"firstLevelChild.firstLevelChildAttrA" : "tooShort"});  

        // Verify there was no change made
        equal( this.parentBBModel.get("firstLevelChild.firstLevelChildAttrA"), "firstLevelChildAttrAValue");

        // The change event should not be triggered because the attribute was never changed (it failed validation)
        ok(!(changeCallbackCalled));
    });

    test("changedAttributes should not include changes from previous change events, especially those that failed validation", function() {
        var changeCallbackCalled = false;

        this.parentBBModel.bind('change:parentAttrA', function(model, errors) {
            changeCallbackCalled = true;
            // Changed attributes should only include parentAttr because firstLevelChild.firstLevelChildAttrA 
            // failed validation and in any case was part of a previous event
            equal( model.changedAttributes(), {"parentAttrA" : "parentAttrAValueChanged"}  ); 
        });

        // Change a nested attribute to invalid value
        this.parentBBModel.set({"firstLevelChild.firstLevelChildAttrA" : "tooShort"});  

        // Verify there was no change made
        equal( this.parentBBModel.get("firstLevelChild.firstLevelChildAttrA"), "firstLevelChildAttrAValue");

        // Change another attribute to a valid value
        this.parentBBModel.set({"parentAttrA" : "parentAttrAValueChanged"});
        ok(changeCallbackCalled);
    });
});
 </script>

    <title></title>
    </head>
    <body>
        <h1 id="qunit-header">
            Backbone-Nested Test
        </h1>
        <h2 id="qunit-banner"></h2>
        <div id="qunit-testrunner-toolbar"></div>
        <h2 id="qunit-userAgent"></h2>
        <ol id="qunit-tests"></ol>
        <!-- THE FIXTURE -->
        <div id="qunit-fixture"></div>
    </body>
</html>

run tests in Node

ensure that the plugin works when a document/window isn't present

Re-setting items on an array within a nested object doesn't work correctly

If you have a nested model with an array, you are unable to change that array once set. I'm taking a look into it - posting the issue for others.

Passing Test:

test("#set() 1-N with an object containing an array", function() {
  doc.set({
    'addresses[0]': {
      city: 'Seattle',
      state: 'WA',
      areaCodes: ['001', '002', '003']
    }
  });
  doc.set({
    'addresses[1]': {
      city: 'Minneapolis',
      state: 'MN',
      areaCodes: ['101', '102', '103']
    }
  });

  deepEqual(doc.get('addresses[0].areaCodes'), ['001', '002', '003']);
  deepEqual(doc.get('addresses[1].areaCodes'), ['101', '102', '103']);
});

Failing Test:

test("#set() 1-N with an object containing an array where array values are being removed", function() {
  doc.set({
    'addresses[0]': {
      city: 'Seattle',
      state: 'WA',
      areaCodes: ['001', '002', '003']
    }
  });
  doc.set({
    'addresses[0]': {
      city: 'Minneapolis',
      state: 'MN',
      areaCodes: ['101']
    }
  });

  deepEqual(doc.get('addresses[0].areaCodes'), ['101']);
  // addresses[0].areaCodes = ['101', '002', '003']
});

Check for type missmatch in values

An error will be raised in the given situation:

Model:

defaults: {
    foo: null,
}

Code:

this.model.add('foo', {bar: 'crash'});

Issue: Uncaught Error: current value is not an array

cannot empty an array

When using NestedModel's set implementation to assign an empty array to an existing array value, the array value is not changed. See example below:

$(function() {
    MyModel = Backbone.NestedModel.extend({
    //MyModel = Backbone.Model.extend({
        defaults : function() {
            return {
                myArray:["first", "second"]
            };
        }
    });


    MyView = Backbone.View.extend({
        initialize: function() {
            this.model.on("change:myArray", this.render, this);

            this.model.set("myArray", []);

            // when using Backbone.NestedModel, myArray stays unmodified and change event is not triggered
            // when using Backbone.Model, myArray is set to [] and change event is triggered
            alert("myArray value is now: " + this.model.get("myArray"));

        },

        render: function() {
            alert("myArray changed: " + this.model.get("myArray"));
        }       
    });

    new MyView({model:new MyModel()});

});

Looking at the NestedModel code, it seems that the _mergeAttrs: function(dest, source, opts, stack) function causes the problem: it should merge attributes from source to dest but only does this when source contains array elements. A quick fix might be something like this:

(backbone-nested-v1.1.2, from line 117)

  _mergeAttrs: function(dest, source, opts, stack){
      opts = opts || {};
      stack = stack || [];

      // fix: empty dest when source is an empty array
      if (source.length == 0) {
          dest = [];
      }

      _.each(source, function(sourceVal, prop){
         [.. rest of code..]

Stackoverflow Error With Large Objects

When using the set method I keep getting a stackoverflow error. The object contains multi-dimensional arrays. It'll be nice either skip the change events or optimize it.

change events for attributes in nested arrays

Would be nice for a special change event to be fired when a specific attribute is changed in any item in a nested array, e.g.

user.bind('change:addresses[].city', function(){
  // user changed one (or more) of their cities
});
user.set({'addresses[1].city': 'New York'});

remove function does not trigger event when removing last element in array

When the remove function is used to remove the last element in an array, the remove event is not triggered.
Example code:

$(function() {
    MyModel = Backbone.NestedModel.extend({
        defaults : function() {
            return {
                myArray:["first"]
            };
        }
    });


    MyView = Backbone.View.extend({
        initialize: function() {
            this.model.on("remove:myArray", this.onRemove, this);

            this.model.remove("myArray[0]");

            // the element is removed, but onRemove function is not called
            alert("myArray value is now: " + this.model.get("myArray"));

        },

        onRemove: function() {
            alert("myArray element removed, array is now: " + this.model.get("myArray"));
        }
    });

    new MyView({model:new MyModel()});

});

I've traced this bug to the function remove: function(attrStr, opts). In this function an evaluation is performed to see if an element is actually removed:

(from version 1.1.2, line 88)

// only trigger if an element is actually being removed
      var trigger = !opts.silent && (val.length > i + 1),
        oldEl = val[i];

The variable 'trigger' will be false when the array (in this case, the variable 'val') only has one element and that one element is to be removed. When changing the evaluation to accomodate for array lengths of 1, this issue is fixed.

// only trigger if an element is actually being removed
      var trigger = !opts.silent && (val.length >= i + 1),
        oldEl = val[i];

unset removes all attributes

unset removes all attributes on a model. It does this because it builds a new attributes object with the appropriate attribute removed, and then passes it to the super class "set" function with option.unset == true. This causes Backbone.Model to remove all attributes from the Model.

default values as functions

It would be nice to have the possibility to allow default: {} to contain functions (also in nested properties).

For example:

var myModel = Backbone.NestedModel.extended({
    id: '',
    properties: {
        weidth: function(){
            return <some_code_here>;
        }
    }
});

don't force full property path when setting a nested property

Hi, is there a way to avoid specifying the full path to the nested property?

For example, I would like something like this to work:

var model = new Backbone.NestedModel();
var nested = new Backbone.NestedModel();
nested.set('foo', 'bar');
model.set('nested', nested);

model.get('nested').get('foo'); // returns 'bar'

model.get('nested.foo') // returns undefined :(

I prefer not to set the full path every time, like model.set('nested.foo', 'bar'), because often times I will have independent modules that are adding their own models without knowing the full path of where they're being added.

Remove doesn't seem to work

I might not be doing this correctly but I have a test case here that seems to fail removing the item

Campaigner = Backbone.NestedModel.extend({
  defaults: function(){
    return {
      campaign_notes: [{body: 'test'}, {body: 'test2'}, {body: 'test3'}, {body: 'test4'}]
    };
  }
});

campaign = new Campaigner();
console.log(campaign.get('campaign_notes'));
campaign.remove('campaign_notes[1]');
console.log(campaign.get('campaign_notes'));

And here is the output:

[Object { body="test"}, Object { body="test2"}, Object { body="test3"}, Object { body="test4"}]
[Object { body="test"}, [Object { body="test"}, Object { body="test3"}, Object { body="test4"}], Object { body="test4"}]

Seems like it is pushing the spliced array back into the element that I wanted to delete. Other than that all my tests seem to have worked well.

Events from model.add are triggered before the value is added to the model

When an 'add' event is triggered after a model.add, the model does not yet contain the new element. Example code:

$(function() {
    MyModel = Backbone.NestedModel.extend({
        defaults : function() {
            return {
                myArray:[]
            };
        }
    });


    MyView = Backbone.View.extend({
        initialize: function() {
            this.model.on("add:myArray", this.onAdd, this);

            this.model.add("myArray", "aNewElement");

            // this alert will show the array containing a 'aNewElement'
            alert("array after add: " + this.model.get("myArray"));

        },

        onAdd: function() {
            // this alert will show the model before the 'aNewElement' was added. 
                        // This behaviour is different from remove events and Backbone.Model's change events
            alert("array in change event: " + this.model.get("myArray"));
        }
    });

    new MyView({model:new MyModel()});

});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.