0

I know we can retrieve models like this.

<input type="text" name="name" id="firstname" ng-model="firstname" />

In this case, I do know that the models name is firstname. In the controller I can now access it with $scope.firstname.

But what if I do not know which models a developer defines inside a ng-model?

What I want to archieve is to get all models set inside a <form> tag.

Little explaination of scenario.

I made a dialog using AngularJS. The content of the dialog can be anything. The problem I currently face is that when you want to submit a form, the values submitted have to be returned inside a callback function.

The content of the form van be anything, the developer decides. So the content might look like this:

<form ng-submit="submit()">
    <strong>Heading</strong>
    <p>Some text content</p>
    <input type="text" ng-model="firstname" name="firstname" />
    <input type="text" ng-model="lastname" name="lastname" />
    <button class="btn" ng-click="cancel()">Cancel</button>
    <button type="submit" class="btn">Submit</button>
</form>

However, is it possible to get all ng-models using AngularJS?

Snippet

(function () {

  angular.module("app", ["dialog"])
  
  .controller("controller", controller);

  function controller($scope, dialog) {
    $scope.openDialog = function () {
      dialog.open({
        template: 'dialog',
        confirm: function (response, scope) {
          console.log(response, scope);
        },
        cancel: function (response, scope) {
            console.log(response, scope);
            scope.close();
        },
        submit: function (response, scope) {
        
        }
      });
    }
  }
  
  angular.module("dialog", [])

    .factory("dialog", function ($rootScope, $http, $injector, $compile, $location, $timeout, $q, $templateCache) {

        // Inject compiler
        $compile = $injector.get('$compile');

        // Shortcut for angular element
        var _ = angular.element;

        // Array with active dialogs
        var dialogs = [];

        // Create a new scope
        var scope = $rootScope.$new();

        // Creates the dialog
        var __construct = {
            new: function (params) {
                var container = _('<div class="dialog-container" />');
                var dialog = _('<dialog />');
                var template = params.template;

                // Throw error if no template has been specified
                if (!template) {
                    console.error("No template given! Create an inline template or create a .html template file.");

                    return;
                }

                // Check if template is an inline template or .html file
                if (template.indexOf('html') !== -1) {
                    template = $http.get(template);

                    template.success(function (template) {
                        __construct.parseTemplate(container, dialog, template);
                    });
                } else {
                
                    var template = $templateCache.get(template);

                    __construct.parseTemplate(container, dialog, template);
                }

                // Set scopes
                __construct.scopes(params)
            },
            /**
             * Appends the template data to the dialog, then appends dialog to the body
             *
             * @param {object}      - Dialog container
             * @param {object}      - Dialog
             * @param {object}      - Template file
             */
            parseTemplate: function (container, dialog, template) {
                // Create DOM data
                dialog.attr("open", "");
                dialog.appendTo(container);
                _(template).appendTo(dialog);
                _('body').append($compile(container)(scope));

                // Push to active dialogs
                dialogs.push(container);
            },
            /**
             * Create scopes and callback functions
             *
             * @param {object}      - Object of given parameters
             */
            scopes: function (params) {
                scope.submit = function () {
                    console.log(scope);
                }
                // Confirm callback
                scope.confirm = function () {

                    // Callback function
                    var confirm = params.confirm;

                    // Returns true
                    return confirm(true, scope);
                },
                // Cancel callback
                scope.cancel = function () {

                    // Callback function
                    var cancel = params.cancel;

                    // Returns true
                    return cancel(false, scope);
                },
                // Close callback
                scope.close = function () {

                    // Destroy the latest dialog inside the dialogs array
                    __destruct.destroy();
                }
            }
        }

        /**
         * Destroys latest dialog.
         * Allways takes the last array item, which has to be the latest dialog.
         */
        var __destruct = {
            destroy: function () {

                // Retrieves and removes last array key
                var dialog = dialogs.pop()

                // Removes the dialog from the document
                _(dialog).remove();
            }
        }

        var __dialog = {
            open: function (params) {            
                __construct.new(params);
            },
            close: function () {

            }
        }

        return __dialog;

    });

})();
/*
    Dialog stylesheet

    @package    ...
    @author     Richard Mauritz
*/

/*
    Match -webkit rules
*/
.dialog-container {
    background: rgba(0, 0, 0, .5);
    position: fixed;
    top: 0;left: 0;
    height: 100%;
    width: 100%;
    z-index: 99999999;
}

dialog {
    position: absolute;
    top: 50%;
    left: 50%;
    right: 0;
    height: auto;
    height: auto;
    height: auto;
    margin: 0;
    border: solid;
    padding: 1em;
    background: white;
    color: black;
    display: block;
    min-width: 350px;
    max-width: 700px;

    -webkit-transform: translate(-50%, -50%);
       -moz-transform: translate(-50%, -50%);
            transform: translate(-50%, -50%);
}

 /*
    Override with own style
 */
dialog {
    border: 0;
    border-radius: 3px;
}

dialog:before,
dialog:after {
    display: table;
    content: " ";
    clear: both;
}

dialog .btn {
    border: 0;
    padding: 6px 40px !important;
    float: right;
    margin-top: 15px;
    margin-right: 5px;
}

dialog .btn-primary {
    background: none;
    text-transform: uppercase;
    color: #009dff !important;
}

dialog .btn-default {
    background: #f1f1f1;
}

dialog .btn-danger {
    background: #dd4b39;
    color: #fff;
}

dialog .btn-primary:hover,
dialog .btn-primary:focus,
dialog .btn-primary:active,
dialog .btn-primary:active:hover,
dialog .btn-primary:active:focus,
dialog .btn-primary:hover, .btn-primary:focus, 
dialog .btn-primary:focus:hover, 
dialog .btn-primary:active, 
dialog .btn-primary:active:hover {
    background: none;
    color: #009dff;
}

dialog .btn-default:hover,
dialog .btn-default:focus,
dialog .btn-default:active,
dialog .btn-default:active:hover,
dialog .btn-default:active:focus {
    background: #f1f1f1;
}

dialog:not([open]) {
    display: none;
}

dialog + .backdrop {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 9999999;
    background: rgba(0,0,0,0.4);
}

._dialog_overlay {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
}

dialog.fixed {
    position: fixed;
    top: 50%;
    transform: translate(0, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app">
  <div ng-controller="controller">
  
    <button id="open" ng-click="openDialog()">Open dialog</button>
  
    <script type="text/ng-template" id="dialog">
      <form ng-submit="submit()">
        <strong>Warning</strong>
        <p>Fill in your firstname and lastname</p>
        <input type="text" ng-model="firstname" name="firstname" />
        <input type="text" ng-model="lastname" name="lastname" />
        <button class="btn" ng-click="cancel()">Cancel</button>
        <button type="submit" class="btn">Submit</button>
      </form>
    </script>
  
  </div>
</div>
Red
  • 6,599
  • 9
  • 43
  • 85
  • 2
    You can bind all ng-models to an object and use that object to check which all ng-model values are initialised – Vivz Sep 25 '17 at 11:39
  • check this link : https://stackoverflow.com/questions/27984808/retrieve-all-inputs-values-from-a-form-angularjs – MohammadJavad Seyyedi Sep 25 '17 at 11:39
  • if you are using jquery then you can get all input elements value inside your form something like https://stackoverflow.com/a/4291032/5621827 – jitender Sep 25 '17 at 11:41
  • @MohammadJavadSeyyedi The first one uses `jQuery`, I want to prevent that if possible. The seconds one I tried. But then it allways needs the same object name. So for example ` – Red Sep 25 '17 at 11:42
  • @jitender Yes, but I dont want to use `jQuery`. – Red Sep 25 '17 at 11:43
  • @Vivz Can you give an example? – Red Sep 25 '17 at 11:43
  • 1
    what about this one https://stackoverflow.com/a/36073750/5621827 – jitender Sep 25 '17 at 11:45
  • @jitender nice one, I didnt know its existence. I think im going to write a solution based on that idea. However, the form name must not be hardcoded. The developer decides what name he attaches to it. So ive to make a little workaround for that. Thanks for pointing to that topic! :) – Red Sep 25 '17 at 11:51
  • You just have to bind the model to an object, In your case obj.firstname and obj.lastname. And in your controller put $scope.obj={}. So if user does not type in the input the above ng-model values will be undefined. Loop through the object to get all the values. – Vivz Sep 25 '17 at 11:54
  • Ah, look my comment to Mohommad. I wanted to prevent it to be hardcoded. If I do it that way, the developer is forced to use that object name. Im going to fix it based on @jitender 's comment. But thanks for your time! :) – Red Sep 25 '17 at 12:02

2 Answers2

1

What about this one stackoverflow.com/a/36073750/5621827jitender

I wrote an solution based on the link posted by @jitender

I wanted the developer to be free in words, names, objects etc.

The submit function now has this code:

scope.submit = function () {
    // Callback function
    var submit = params.submit;

    // Get current dialog
    // Every newly created dialog will be pushed to the dialogs array
    // Code below gets the last array item
    var dialog = dialogs[dialogs.length - 1]; 

    // Array which will store the form data
    var formValues = [];
    // Get form by name
    var formName = _(dialog).find("form").attr("name");
    // Get form scope
    var formScope = scope[formName];

    // Get form elements
    angular.forEach(formScope, function (element, name) {
        if (!name.startsWith('$')) {
            var obj = {};
            obj[name] = scope[name];

            // Store into formValues
            formValues.push(obj);
        }
    });

    return submit(formValues, scope);
}

Working demo

(function () {

  angular.module("app", ["dialog"])
  
  .controller("controller", controller);

  function controller($scope, dialog) {
    $scope.openDialog = function () {
      dialog.open({
        template: 'dialog',
        confirm: function (response, scope) {
          console.log(response, scope);
        },
        cancel: function (response, scope) {
            console.log(response, scope);
            scope.close();
        },
        submit: function (response, scope) {
            console.log(response);
        }
      });
    }
  }
  
  angular.module("dialog", [])

    .factory("dialog", function ($rootScope, $http, $injector, $compile, $location, $timeout, $q, $templateCache) {

        // Inject compiler
        $compile = $injector.get('$compile');

        // Shortcut for angular element
        var _ = angular.element;

        // Array with active dialogs
        var dialogs = [];

        // Create a new scope
        var scope = $rootScope.$new();

        // Creates the dialog
        var __construct = {
            new: function (params) {
                var container = _('<div class="dialog-container" />');
                var dialog = _('<dialog />');
                var template = params.template;

                // Throw error if no template has been specified
                if (!template) {
                    console.error("No template given! Create an inline template or create a .html template file.");

                    return;
                }

                // Check if template is an inline template or .html file
                if (template.indexOf('html') !== -1) {
                    template = $http.get(template);

                    template.success(function (template) {
                        __construct.parseTemplate(container, dialog, template);
                    });
                } else {
                
                    var template = $templateCache.get(template);

                    __construct.parseTemplate(container, dialog, template);
                }

                // Set scopes
                __construct.scopes(params)
            },
            /**
             * Appends the template data to the dialog, then appends dialog to the body
             *
             * @param {object}      - Dialog container
             * @param {object}      - Dialog
             * @param {object}      - Template file
             */
            parseTemplate: function (container, dialog, template) {
                // Create DOM data
                dialog.attr("open", "");
                dialog.appendTo(container);
                _(template).appendTo(dialog);
                _('body').append($compile(container)(scope));

                // Push to active dialogs
                dialogs.push(container);
            },
            /**
             * Create scopes and callback functions
             *
             * @param {object}      - Object of given parameters
             */
            scopes: function (params) {
                // Submit callback
                scope.submit = function () {
                    // Callback function
                    var submit = params.submit;

                    // Get current dialog
                    var dialog = dialogs[dialogs.length - 1];

                    // Get form scope by name
                    var formValues = [];
                    var formName = _(dialog).find("form").attr("name");
                    var formScope = scope[formName];

                    // Get form elements
                    angular.forEach(formScope, function (element, name) {
                        if (!name.startsWith('$')) {
                            var obj = {};
                            obj[name] = scope[name];

                            formValues.push(obj);
                        }
                    });

                    return submit(formValues, scope);
                }
                // Confirm callback
                scope.confirm = function () {

                    // Callback function
                    var confirm = params.confirm;

                    // Returns true
                    return confirm(true, scope);
                },
                // Cancel callback
                scope.cancel = function () {

                    // Callback function
                    var cancel = params.cancel;

                    // Returns true
                    return cancel(false, scope);
                },
                // Close callback
                scope.close = function () {

                    // Destroy the latest dialog inside the dialogs array
                    __destruct.destroy();
                }
            }
        }

        /**
         * Destroys latest dialog.
         * Allways takes the last array item, which has to be the latest dialog.
         */
        var __destruct = {
            destroy: function () {

                // Retrieves and removes last array key
                var dialog = dialogs.pop()

                // Removes the dialog from the document
                _(dialog).remove();
            }
        }

        var __dialog = {
            open: function (params) {            
                __construct.new(params);
            },
            close: function () {

            }
        }

        return __dialog;

    });

})();
/*
    Dialog stylesheet

    @package    ...
    @author     Richard Mauritz
*/

/*
    Match -webkit rules
*/
.dialog-container {
    background: rgba(0, 0, 0, .5);
    position: fixed;
    top: 0;left: 0;
    height: 100%;
    width: 100%;
    z-index: 99999999;
}

dialog {
    position: absolute;
    top: 50%;
    left: 50%;
    right: 0;
    height: auto;
    height: auto;
    height: auto;
    margin: 0;
    border: solid;
    padding: 1em;
    background: white;
    color: black;
    display: block;
    min-width: 350px;
    max-width: 700px;

    -webkit-transform: translate(-50%, -50%);
       -moz-transform: translate(-50%, -50%);
            transform: translate(-50%, -50%);
}

 /*
    Override with own style
 */
dialog {
    border: 0;
    border-radius: 3px;
}

dialog:before,
dialog:after {
    display: table;
    content: " ";
    clear: both;
}

dialog .btn {
    border: 0;
    padding: 6px 40px !important;
    float: right;
    margin-top: 15px;
    margin-right: 5px;
}

dialog .btn-primary {
    background: none;
    text-transform: uppercase;
    color: #009dff !important;
}

dialog .btn-default {
    background: #f1f1f1;
}

dialog .btn-danger {
    background: #dd4b39;
    color: #fff;
}

dialog .btn-primary:hover,
dialog .btn-primary:focus,
dialog .btn-primary:active,
dialog .btn-primary:active:hover,
dialog .btn-primary:active:focus,
dialog .btn-primary:hover, .btn-primary:focus, 
dialog .btn-primary:focus:hover, 
dialog .btn-primary:active, 
dialog .btn-primary:active:hover {
    background: none;
    color: #009dff;
}

dialog .btn-default:hover,
dialog .btn-default:focus,
dialog .btn-default:active,
dialog .btn-default:active:hover,
dialog .btn-default:active:focus {
    background: #f1f1f1;
}

dialog:not([open]) {
    display: none;
}

dialog + .backdrop {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 9999999;
    background: rgba(0,0,0,0.4);
}

._dialog_overlay {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
}

dialog.fixed {
    position: fixed;
    top: 50%;
    transform: translate(0, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app">
  <div ng-controller="controller">
  
    <button id="open" ng-click="openDialog()">Open dialog</button>
  
    <script type="text/ng-template" id="dialog">
      <form ng-submit="submit()" name="testForm">
        <strong>Warning</strong>
        <p>Fill in your firstname and lastname</p>
        <input type="text" ng-model="firstname" name="firstname" />
        <input type="text" ng-model="lastname" name="lastname" />
        <button class="btn" ng-click="cancel()">Cancel</button>
        <button type="submit" class="btn">Submit</button>
      </form>
    </script>
  
  </div>
</div>
Red
  • 6,599
  • 9
  • 43
  • 85
1

I'm not sure if I understand your question clearly, however, it sounds like you're trying to access the model created by the form inputs on submit. I normally do something like the following:

<div class="form-group">
      <label class="col-md-3 control-label">Company Title:
      <span class="required" aria-required="true"> * </span></label>
      <div class="col-md-4">
        <input type="text" ng-model="reg.company_title" name="company_title" class="form-control" ng-class="{'has-error': ng-invalid}"
          ng-required="true">
        <span class="help-block"> This is the name customers will see online. </span>
      </div>
      <div ng-messages="registrationForm.company_title.$error" ng-if="registrationForm.company_title.$dirty">
        <span ng-message="required" class="registration-error">This field is required.</span>
      </div>
</div>

This may be a little bit more than you need to see, but I literally just copied it from a project and I'm too lazy to delete the extra stuff.

So as you can see, my ng-model says 'registration.company_title'. That allows me to access $scope.registration.company_title from the controller. The angular documentation has a good example of what I'm saying here

Also, you can see the whole form in action here.

So, if you have a collection of input fields you want to access in your controller, set them to fields on an object like above. Hope that helps!

insaineyesay
  • 336
  • 2
  • 7
  • As I stated. I know I can access the models like that. I only don't know the names of the models. Thats up to the developer. So getting them the way you do is not an option for me. Thanks for your time though :) – Red Sep 25 '17 at 13:04
  • oh. sorry! well maybe you can have the inputs set variables on the scope that are used dynamically in the model. Something like this maybe: https://stackoverflow.com/questions/12553617/how-can-i-set-a-dynamic-model-name-in-angularjs – insaineyesay Sep 25 '17 at 13:08