Delegating a function call in Javascript
Asked Answered
M

2

9

Is there a way in Javascript to have a delegate like the ones in c# ?

Example in c#

Object.onFunctionCall = delegate (vars v) {
    Console.WriteLine("I can do something in this private delegate function");
};

I would like with my Javascript to have my main object do something over a long time, and shot a delegate once in a while to give a little update. All that without having to change the code itself of my class to adjust for the webpage.

function mainObject() {
    this.onUpdate = function() { //Potentially the delegate function here
    }
}

var a = new mainObject();
a.onUpdate = Delegate {
      $(".myText").text("Just got a delegate update");
} 

I dunno if it's clear enough.. havent found ressources on this so I suppose there is just no way to do so ?

NOTE: I am not looking into jquery Click delegates event here, but into delegating a function call like how it works in c#

Let me know

Morphia answered 12/4, 2015 at 4:44 Comment(7)
All functions in JavaScript (created with function ..) are 'delegates' - that is, they are First Class Functions. You may also be interested in Function.bind, such that the this context is preserved (which is more C#-delegate-like). Also read through the related questions.Hystero
Do you have an example of a function that 'Auto fires' itself, like the one stated in c# ?Morphia
The JavaScript code shown would "work" as-is, if replacing Delegate { with function () {. For instance, at the bottom: calling a.onUpdate() would updated the text. If talking about events in C# (which are not delegates themselves) then that is a different concept. The example C# code shown won't "auto fire" .. not sure what is meant.Hystero
What do you mean by "auto fires?" The delegate on its own just exists and waits for invocation. There is a common pattern for immediately invoked functions in JavaScript, but it's not really clear whether that's what you're looking for.Heterocyclic
OP, you should provide a link in the question to a definition of this "delegate" thing so non-C# people can better understand what you are asking.Dipstick
If I understand the question correctly, the Observer Pattern may be of interest. At the end of the article are links to other common design patterns used in javascript - all well worth learning.Dipstick
@Dipstick Thanks alot for this usefull information, the Observer pattern was exactly was i was looking for. Seemed complicated at start, but the Object oriented design used inside this Pattern was what i was looking for. Now the end user can simply add observer class and do whatever he wants when the function gets called. You may want to formulate a nice awnser as i will accept it whenever its there.Morphia
D
7

What you are looking for is an "Observer Pattern", as described eg. here.

But as you are interested in jQuery, you don't need to go the trouble of writing an observer pattern for yourself. jQuery already implements an observer in the guise of its .on() method, which can be invoked on a jQuery collection to cause callback function(s) to fire every time a native or custom event is dispatched.

Here's an example :

$(function() {
    //attach a custom event handler to the document
    $(document).on('valueChange', function (evt) {
        $(this).find("#s0").text(evt.type);
        $(this).find("#s1").text(evt.value);
        $(this).find("#s2").text(evt.change);
        $(this).find("#s3").text(evt.timestamp).toLocaleString();
    });

    //customEvent(): a utility function that returns a jQuery Event, with custom type and data properties
    //This is necessary for the dispatch an event with data
    function customEvent(type, data) {
        return $.extend($.Event(type||''), data||{});
    };

    //randomUpdate(): fetches data and broadcasts it in the form of a 'changeValue' custom event
    //(for demo purposes, the data is randomly generated)
    function randomUpdate() {
        var event = customEvent('valueChange', {
            value: (10 + Math.random() * 20).toFixed(2),
            change: (-3 + Math.random() * 6).toFixed(2),
            timestamp: new Date()
        });
        $(document).trigger(event);//broadcast the event to the document
    }
});

Here's a demo, complete with "start" and "stop" buttons for a regular "interval" dispatch of the custom event.

Notes

  • Under some circumstances, it might be more appropriate to broadcast the event to the four data spans individually.
  • On the web, you will find mention of a more convenient jQuery.event.trigger({...}) syntax. Unfortunately this was an undocumented feature of jQuery, which disappeared at v1.9 or thereabouts.
Dipstick answered 13/4, 2015 at 13:55 Comment(1)
5 years later - just realised that $(this).find("#s3").text(evt.timestamp).toLocaleString(); should be $(this).find("#s3").text(evt.timestamp.toLocaleString());Dipstick
S
8

Although the original question was answered by solving the root problem (observer - pattern) there is a way to implement delegates in JavaScript.

The C# delegate pattern is available in native JavaScript using context binding. Context binding in JavaScript is done with the .call method. The function will be called in the context given by the first argument. Example:

function calledFunc() {
  console.log(this.someProp);
}

var myObject = {
  someProp : 42,
  doSomething : function() {
    calledFunc.call(this);
  }
}

myObject.doSomething();
// will write 42 to console;
Surrebutter answered 4/1, 2019 at 9:34 Comment(0)
D
7

What you are looking for is an "Observer Pattern", as described eg. here.

But as you are interested in jQuery, you don't need to go the trouble of writing an observer pattern for yourself. jQuery already implements an observer in the guise of its .on() method, which can be invoked on a jQuery collection to cause callback function(s) to fire every time a native or custom event is dispatched.

Here's an example :

$(function() {
    //attach a custom event handler to the document
    $(document).on('valueChange', function (evt) {
        $(this).find("#s0").text(evt.type);
        $(this).find("#s1").text(evt.value);
        $(this).find("#s2").text(evt.change);
        $(this).find("#s3").text(evt.timestamp).toLocaleString();
    });

    //customEvent(): a utility function that returns a jQuery Event, with custom type and data properties
    //This is necessary for the dispatch an event with data
    function customEvent(type, data) {
        return $.extend($.Event(type||''), data||{});
    };

    //randomUpdate(): fetches data and broadcasts it in the form of a 'changeValue' custom event
    //(for demo purposes, the data is randomly generated)
    function randomUpdate() {
        var event = customEvent('valueChange', {
            value: (10 + Math.random() * 20).toFixed(2),
            change: (-3 + Math.random() * 6).toFixed(2),
            timestamp: new Date()
        });
        $(document).trigger(event);//broadcast the event to the document
    }
});

Here's a demo, complete with "start" and "stop" buttons for a regular "interval" dispatch of the custom event.

Notes

  • Under some circumstances, it might be more appropriate to broadcast the event to the four data spans individually.
  • On the web, you will find mention of a more convenient jQuery.event.trigger({...}) syntax. Unfortunately this was an undocumented feature of jQuery, which disappeared at v1.9 or thereabouts.
Dipstick answered 13/4, 2015 at 13:55 Comment(1)
5 years later - just realised that $(this).find("#s3").text(evt.timestamp).toLocaleString(); should be $(this).find("#s3").text(evt.timestamp.toLocaleString());Dipstick

© 2022 - 2024 — McMap. All rights reserved.