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:
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.
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.
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>');
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:
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.
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.
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:
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:
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.
Back end:
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:
However adding a directive does:
The error I see in the console is:
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.
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:
Let me know if this worked.
Cheers, Josef
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:
});
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:
I see only this in this inspector in the front end, and my button obviously disappears:
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
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:
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?
Some observations:
link
function for your frontend directive. You can just usetemplate
ortemplateUrl
instead, unless you are doing something fairly sophisticated (it does not appear that you are).data
andopts
in your scope. The only data you should really be interested in should be inconfiguration
andfieldModels
. 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:
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).
is working on a reply...