Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • John Daugherty 5 posts 87 karma points
    Jul 26, 2017 @ 01:16
    John Daugherty
    0

    Error adding directive

    I'm attempting to create a new custom formulate field and getting an error when I try rendering on the screen with extra non-default functionality.

    I've made the IFormFieldType that definitely gets hit when I debug with a breakpoint in Visual Studio, and my field is also showing up in the Umbraco back office. I'm able to put that field into a form and when I do nothing else, I can see a text field rendered on the front end, so up to that point, it's working.

    public class MultiTextField : IFormFieldType
    {
        public string Directive => "formulate-multitext-field";
        public string TypeLabel => "MultiText";
        public string Icon => "icon-documents";
        public Guid TypeId => new Guid("d8ff5b99-f049-4608-87a2-b72293cce3ff");
        public object DeserializeConfiguration(string configuration)
        {
            return null;
        }
    
        public string FormatValue(IEnumerable<string> values, FieldPresentationFormats format, object configuration)
        {
            throw new NotImplementedException();
        }
    }
    

    Back end:

    Formulate back end

    Front end:

    Formulate front end

    The problem is when I want to add a directive to it with app.directive in my form rendering cshtml file (I'm using the default from the formulate.rocks documentation page) in order to make extra functionality on the front end, I'm getting an error.

    Adding a controller gives no error:

        app.controller("MultiTextField", FormulateMultiFieldController);
    

    However adding a directive does:

        app.directive("MultiTextField", function () {
            return {
                restrict: "AEC",
                replace: true,
                // Note that it's "templateUrl" rather than "template".
                templateUrl: "/Scripts/BDL_Scripts/MultiTextField.html",
                controller: FormulateMultiFieldController,
                scope: {
                    configuration: "="
                }
            };
        });
    

    The error I see in the console is:

    angular.js:38 Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.4.8/$injector/modulerr?p0=app&p1=Error%3A%20%…ogleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.4.8%2Fangular.min.js%3A20%3A274)
    at angular.js:38
    at angular.js:4458
    at n (angular.js:340)
    at g (angular.js:4419)
    at eb (angular.js:4344)
    at c (angular.js:1676)
    at yc (angular.js:1697)
    at Zd (angular.js:1591)
    at HTMLDocument.<anonymous> (angular.js:29013)
    at j (jquery.js:3099)
    

    I know I'm probably missing something simple, but I'm a little confused by the documentation so I don't know what it might be.

  • Josef Kohout 3 posts 75 karma points
    Jul 26, 2017 @ 16:48
    Josef Kohout
    0

    Hi John,

    There are 2 posible issues:

    1) Your directive must start with lowercase letter MultiTextField needs to be renamed multiTextField. Please see (https://docs.angularjs.org/guide/directive#normalization)

    2) Based on the error message. I think, that you maybe missing a module. Ensure that formulate module is declared during app creation step.

    3) Ensure that the field is registered with FormulateFieldTypesProvider.

    Your app setup should look something like this:

    'use strict';
    
    var angular = require('angular');
    
    // Create Angular app.
    var app = angular.module('app', ['formulate']);
    
    app.config(function (FormulateFieldTypesProvider) {
    
    // Register custom field types
    FormulateFieldTypesProvider
        .setOptions({prependLabel: false})
        .register('MultiTextField', '<multi-text-field></multi-text-field>');
    

    Let me know if this worked.

    Cheers, Josef

  • John Daugherty 5 posts 87 karma points
    Jul 27, 2017 @ 12:57
    John Daugherty
    0

    Thank you very much for your help, this did work, but now my question is how do I use angular directives in my HTML template code now?

    For example, if I use the code below:

    app.directive("multiTextField", function ($compile) {
    return {
        restrict: "AEC",
        replace: true,
        controller: FormulateMultiFieldController,
        scope: {
            data: "=",
            opts: "=",
            configuration: "="
        },
        link: function (scope, elem, attrs) {
            var html = '<a ng-click="addData(field.id)"><div class ="btn btn-success"><span>Add Field</span></div></a>';
    
            var el = $compile(html)(scope);
    
            elem.append(el);
        }
    };
    

    });

    I can see my "Add Field" button, and my "addData" function in my controller gets called fine, but the "field.id" variable comes through as null.

    When I put a break right at the beginning of the "link" function, I can successfully see my scope variables that I set up in the controller, so I can tell at least that works correctly.

    Additionally, if I wrap the A tag with a very simple top-level "ng-repeat" such as:

                    var html = '<div class="row ib top" ng-repeat="row in ctrl.formData.rows"><a ng-click="addData(field.id)"><div class ="btn btn-success"><span>Add Field</span></div></a></div>';
    

    I see only this in this inspector in the front end, and my button obviously disappears:

    Inspector

  • Josef Kohout 3 posts 75 karma points
    Jul 27, 2017 @ 16:43
    Josef Kohout
    0

    Hi John,

    I'll start working on that documentation. Your question is shining a light on things that I failed to document.

    I suspect the main problem is the isolated scope in your directive multi-text-field. This will break formulateField directive that is responsible for creating instance of the specific 'field' directive and its scope.

    https://github.com/rhythmagency/formulate/blob/master/src/formulate.app/JavaScript/FormTemplates/responsive.bootstrap.angular/directives/form/field.js

    Once you remove the scope property from your directive, then just console.log(scope) in the link function, and you should be able to see all data being attached to that scope.

    Cheers, Josef

  • John Daugherty 5 posts 87 karma points
    Jul 28, 2017 @ 19:13
    John Daugherty
    0

    Do you know where that isolated scope directive comes from? I don't see where I have that in my code - I literally copied the app.config line you sent over:

            app.config(function (FormulateFieldTypesProvider) {
    
            // Register custom field types
            FormulateFieldTypesProvider
                .setOptions({ prependLabel: false })
                .register('MultiTextField', '<multi-text-field></multi-text-field>');
        });
    

    And I don't see anywhere that I have it in my controller.

    I'll take a look at the link you provided and see if I can adapt it to my usage and maybe that will get rid of the isolated scope directive?

  • Nicholas Westby 2045 posts 7032 karma points c-trib
    Jul 28, 2017 @ 20:36
    Nicholas Westby
    0

    Some observations:

    • Deux-rectives. You will need two AngularJS directives. One for the back office and one for when you render the form on the frontend of your website. Just wanted to be sure you weren't trying to combine the two, as they would be very different.
    • Unlink. You should not need to use a link function for your frontend directive. You can just use template or templateUrl instead, unless you are doing something fairly sophisticated (it does not appear that you are).
    • Scope. It's unclear to me why you'd want data and opts in your scope. The only data you should really be interested in should be in configuration and fieldModels. Additionally, I expect you would not need to specify anything on the scope, because if you do not specify a scope you will get everything on the parent scope.

    FYI, this is the bit of code that is causing the scope to be isolated:

    scope: {
        data: "=",
        opts: "=",
        configuration: "="
    },
    

    Delete those lines and your scope should no longer be isolated (Josef can correct me if I'm wrong about that, but I believe that's what you'd do).

Please Sign in or register to post replies

Write your reply to:

Draft