Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I am creating a scavenger hunt editor that will contain many different questions. Also, each question can be of different type. Therefore, I have one array of questions and I do an ng-repeat to show all the questions.

To do so, I have a javascript object that represent a Question. This question can be inherited by different question types.

I have one specific question type, that is slidingPuzzle, which will require an image to be uploaded. My problem arrives here, I want to be able to call a function, inside this object, when the input file changes.

I want here to put the emphasis on the fact that it cannot be a general function declared in the scope !

Here's how my structure looks like (http://plnkr.co/edit/lnJ8rAlpP0xJ3aM2HZ7o?p=preview):

HTML:

      <div class="question" ng-repeat="question in scavengerHunt.questions">

        <div class="chooseQuestionType">
          Question type:
          <select ng-change="question.setChild()" ng-model="question.subClass">
            <option value="slidingPuzzleQuestion">slidingPuzzleQuestion</option>
          </select>
        </div>
        <div class="questionContainer">
            <div class="puzzleContainer">

                  <input type="file" name="image" id="puzzleContainerImage" ng-file-select="question.child.imageFileSelected()">

            </div>
        </div>

AngularJS Model:

var scavengerHuntApp = angular.module('scavengerHuntApp', []);

scavengerHuntApp.controller('QuestionsCtrl', function ($scope) {
  function ScavengerHunt() {
                var self = this;

                self.questions = [];


                self.addQuestion = function(question) {
                    self.questions.push(question);
                }

            }
  function Question() {
                var self = this;

                self.id = 0;
                self.subClass = "slidingPuzzleQuestion";


                self.child = "";

                self.setChild = function() {
                    var type = self.subClass;

                    if(type == 'slidingPuzzleQuestion'){
                        self.child = new SlidingPuzzleQuestion();
                    }

                }
            }

            function SlidingPuzzleQuestion() {
                var self = this;


                self.imageFileSelected = function () {
                    console.log()
                };



            }


            //Utilities function
            $scope.addEmptyQuestion = function() {
                $scope.scavengerHunt.addQuestion(new Question());
            }

            $scope.scavengerHunt = new ScavengerHunt();

            $scope.addEmptyQuestion();

});

AngularJS Directive

Up to now, I figured that I would probably have to use an AngularJS directive, since the ng-change does not work currently with input file (https://github.com/angular/angular.js/issues/1375). Hence, the following code does not work since in the html tag ng-file-select="question.child.imageFileSelected()" , I have a context that is lost when trying to bind the element to a function.

  scavengerHuntApp.directive("ngFileSelect",function(){

            return {
                link: function (scope, element, attrs) {

                    console.log(scope);
                    console.log(element);
                    var onChangeFunc = element.scope()[attrs.customOnChange];
                    element.bind('change', onChangeFunc); 

                }

            }


        });

So, is there a way to pass the current context in the html code to bind it to a particular object ?

I hope everything is clear enough, if not let me know and I'll clarify as much as possible !

share|improve this question
    
Can you please elaborate why it cannot be a general function declared in the scope? – Mr_Mig Feb 26 '14 at 15:10
    
Because it is part of my architecture design. I showed a small part of the code but mainly it cannot be a general function. – CoachNono Feb 26 '14 at 15:20
up vote 3 down vote accepted

Ok, have a look at this plunker: http://plnkr.co/edit/qPK6EmAkt39QoZFZ5Sa3?p=preview

I have removed some of your code just to let you understand what's going on low level.

You can use isolated scope with callback attribute binding using & symbol. What it does is it registers the expression in the attribute as a callable function inside the isolated scope of the directive.

The rules are:

  1. You register isolated scope

    scope : {
        myAttr : "&"
    }
    
  2. You specify the attribute in the form

    my-attr="object.objectMethod(param1, param2)"
    
  3. Angular wraps the objectMethod with the callable wrapper

  4. When needed, you call the wrapper like this:

    scope.myAttr({param1: "value", param2:"value"})
    
  5. Angular transforms this call into actual object.objectMethod call with parameters specified
share|improve this answer
    
That's amazing ! Thank you ! – CoachNono Feb 27 '14 at 20:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.