5

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 !

2
  • Can you please elaborate why it cannot be a general function declared in the scope? Commented Feb 26, 2014 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. Commented Feb 26, 2014 at 15:20

1 Answer 1

4

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.