Meteor JS Autoform Custom Input - There is no current view - javascript

I'm creating my own custom input type for autoform in meteor js. Everything works as it should, but I get a weird error in browser's console. This custom input is a bootstrap dropdown multi checkbox with possibility of being nested in other bootstrap dropdowns. Error occurs when you check any field inside dropdown.
Uncaught Error: There is no current view
Blaze._getCurrentView
Blaze.getView
AutoForm.templateInstanceForForm
_validateField
_.throttle.later
Here is my coffee file used for custom input.
AutoForm.addInputType "dropdownMultiCheckbox",
template: "afDropdownMultiCheckbox"
valueOut: () ->
grabInput = $(#).children().children('input:checked')
holder = []
grabInput.each ->
holder.push $(#).val()
if $(grabInput[0]).hasClass('all-selector')
holder.shift()
holder
SimpleSchema.messages
'atLeastOne': 'You need to select at least one field'
Template.afDropdownMultiCheckbox.helpers
options: ->
options = #.selectOptions
options
dsk: () ->
#.atts["data-schema-key"]
Template.afDropdownMultiCheckbox.events
'click div.dropdown-toggle': (event) ->
$(event.target).siblings("ul.dropdown-menu").toggle()
'click .all-selector': (event) ->
if event.target.checked
$(event.target).parent().siblings().children(".checkbox-options").prop('checked',true)
else
$(event.target).parent().siblings().children(".checkbox-options").prop('checked',false)
'click .checkbox-options': (event,templateInstance) ->
if !(event.target.checked)
$(event.target).parent().siblings().children(".all-selector").prop('checked',false)
if $(".check-onclick-#{#.class}:checked").length == $(".check-onclick-#{#.class}").length
$("#checkbox-all-#{templateInstance.data.atts.id}").prop('checked',true)
'click div.btn.btn-default.dropdown-toggle,ul,ul *': (event) ->
event.stopPropagation()
Template.afDropdownMultiCheckbox.rendered = ->
instanceOfTemplate = #
$("*").on "click", (event) ->
if !($(event.target)[0] == $(".class-#{instanceOfTemplate.data.atts.id}")[0] ||
$(event.target)[0] == $("##{instanceOfTemplate.data.atts.id}")[0] ||
$(event.target).hasClass("close-dropdown-multi"))
$(".class-#{instanceOfTemplate.data.atts.id}").hide()
jade file below:
template(name="afDropdownMultiCheckbox")
.dropdown
.btn.btn-default.dropdown-toggle(type="button", id="{{atts.id}}", aria-expanded="false")
| {{atts.buttonText}}
span.caret
ul.dropdown-menu(role="menu", aria-labelledby="{{atts.id}}",class="class-{{atts.id}}")
form
div(data-schema-key="{{dsk}}")
if atts.allOption.presence
li.close-dropdown-multi(role="presentation")
input.all-selector.close-dropdown-multi(type="checkbox", value="{{atts.allOption.value}}", id="checkbox-all-{{atts.id}}", role="menuItem")
label.close-dropdown-multi(for="checkbox-all-{{atts.id}}") {{atts.allOption.value}}
+each options
li.close-dropdown-multi(role="presentation")
input.close-dropdown-multi.checkbox-options(class="check-onclick-#{this.class}", role="menuItem", type="checkbox", value="#{this.text}", id="checkbox-#{this.text}")
label.close-dropdown-multi(for="checkbox-#{this.text}") {{this.text}}
br
Schema file I use:
categories:
type: [String]
optional: false
custom: ->
if this.value.length == 0
'atLeastOne'
autoform:
buttonText: 'Categories'
label: false
id: 'dropdown-nr-1'
options: -> _.map CampaignCategories, (arg1) ->
option =
text: t "campaign.categories.#{arg1}"
class: 'dropdown-vol-1'
allOption:
presence: false
value: 'All'
afFieldInput:
type: 'dropdownMultiCheckbox'
locations:
type: [String]
optional: false
custom: ->
if this.length == 0
'atLeastOne'
autoform:
buttonText: 'Locations'
label: false
id: 'dropdown-nr-2'
allOption:
presence: true
value: 'All'
options: -> _.map CampaignLocations, (arg1) ->
option =
text: t "campaign.locations.#{arg1}"
class: 'dropdown-vol-2'
afFieldInput:
type: 'dropdownMultiCheckbox'
EDITED:
Error is caused by CampaignLocations array in schema which is used for i18n in meteor app. It's global variable, maybe someway it's changing meteor context (and this value) because it loads variable outside current template. If I return static value like this below:
[{text: 'test',class: 'test'},{text: 'test',class: 'test'},{text: 'test',class: 'test'}]
Everything is ok and there is no error.

I solved the problem. The problem was very simple but "thanks" to the way that javascript (and meteor) shows errors I didn't notice that I tried to nest form inside form, this is why "Uncaught Error: There is no current view" occured.
What caught me completely off guard was the moment when error appeared in my chrome console. Meteor will not complain with errors when using autoform and nesting form tag inside form tag when "options" property is generated with static data like this
[{text: 'test',class: 'test'},{text: 'test',class: 'test'},{text: 'test',class: 'test'}]
But if you will use for example this kind of code inside options property:
options: -> _.map CampaignLocations, (arg1) ->
option =
text: t "campaign.locations.#{arg1}"
class: 'dropdown-vol-2'
Which is using interpolation or string concatenation then Meteor will throw the error.

Related

In sails, how to handle "nulls" in a JSON field in a database?

Well say I have a database that has a schema like:
CREATE TABLE public.mytable
(
datacolumn json,
id serial NOT NULL,
PRIMARY KEY (id)
)
Clearly datacolumn can be null: null is even an important value of this.
Now in sails I have a datamodel defined as:
moduel.exports = {
attributes: {
datacolumn: {
type: 'ref',
columnType: 'json',
allowNull: true,
},
},
id: {
type: 'number',
},
}
This should work right? - Well it doesn't sails refuses to lift:
Failed to lift app: userError: The attribute datacolumn on the mytable model contains invalid properties. The allowNull flag may not be used on attributes with type json or type ref.
I could of course just remove the line allowNull: but that would give lots of warnings that null is not a valid value (directly logged, and giving like 10 lines per warning). And I doubt it will correctly insert null values would it?
So how to handle above database schema?

How to handle Laravel to Vue.js boolean values

I've got an input field that looks like the following :
<tr v-for="(item, index) in collection">
...
<input
type="checkbox"
v-model="item.activated"
#change="toggleSwitch(item.resource_url, 'activated', item)">
>
...
</tr>
The collection is an array containing several keys, activated is one of them. activated is equal to 1 or 0 as the data is coming from a mysql database. The problem is that the input field is always set to true in this case, even if the activated is equal to 1 or 0.
Now, I tried writing the v-model like so to fix the issue :
v-model="!!+item.activated"
as by adding !!+ I'd convert the integer value to a boolean and use that. That fixes the issue, but creates another. The other issue I get by doing so is when I try to change my checked input I get an error :
[Vue warn]: Cannot set reactive property on undefined, null, or primitive value: false
admin.js:120238 TypeError: Cannot use 'in' operator to search for 'activated' in false
The toggleSwitch method looks like this :
toggleSwitch: function toggleSwitch(url, col, row) {
var _this8 = this;
axios.post(url, row).then(function (response) {
_this8.$notify({ type: 'success' });
}, function (error) {
row[col] = !row[col];
_this8.$notify({ type: 'error' });
});
},
I'm new to Vue.js, any idea how to debug this and where could my problem be coming from? I'll gladly give any additional info.
Edit :
Here's my component
Vue.component('profile-edit-profile-form', {
mixins: [AppForm],
data: function() {
return {
form: {
...
activated: false ,
...
}
}
}
});
If you use AJAX to populate your collection, then you should convert your 0 and 1 strings to booleans in your AJAX callback before injecting them into your component. Or even better you could convert them directly from your controller, by the way you directly get true|false
data.forEach(function(entry) {
if(entry.hasOwnProperty("activated"))
entry.activated = !!+entry.activated
});
my recommendation is:
Database column "activated" tinyint(1)
in laravel model use $cast array to cast "activated" to "boolean"
in vue use native type boolean for form.activated with true and false
Laravel Model:
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'minimum' => 'float',
'maximum' => 'float',
'step' => 'float',
'minItems' => 'integer',
'maxItems' => 'integer',
'uniqueItems' => 'boolean',
];
Vue:
<b-form-radio-group id="uniqueItems" v-model="formData.uniqueItems" :options="optionsBoolean" name="uniqueItems" :/>
optionsBoolean (){
return [
{ text: 'Yes'), value: true },
{ text: 'No'), value: false }
]
}

Using Ag-Grid Enterprise license getting a 'ag-grid: Looking for component [agSetColumnFilter] but it wasn't found." error

I've been using Ag-Grid's Enterprise feature "agSetColumnFilter" for months with no problem.
I'm using the following versions:
"ag-grid": "^17.1.1",
"ag-grid-enterprise": "^17.1.1",
"ag-grid-react": "^17.1.0",
After a bit of refactoring, I'm starting to get this error after just clicking on the filter menu:
ag-grid: Looking for component [agSetColumnFilter] but it wasn't found.
Array.concat.ComponentProvider.retrieve # componentProvider.js?6ebb:209
Array.concat.ComponentResolver.resolveByName # componentResolver.js?1587:159
Array.concat.ComponentResolver.getComponentToUse # componentResolver.js?1587:155
Array.concat.ComponentResolver.newAgGridComponent # componentResolver.js?1587:271
Array.concat.ComponentResolver.createAgGridComponent # componentResolver.js?1587:236
Array.concat.FilterManager.createFilterInstance # filterManager.js?d1c0:376
Array.concat.FilterManager.createFilterWrapper # filterManager.js?d1c0:393
Array.concat.FilterManager.getOrCreateFilterWrapper # filterManager.js?d1c0:343
Array.concat.StandardMenuFactory.showPopup # standardMenu.js?505d:52
Array.concat.StandardMenuFactory.showMenuAfterButtonClick # standardMenu.js?505d:45
Array.concat.HeaderComp.showMenu # headerComp.js?f669:122
(anonymous) # headerComp.js?f669:107
componentResolver.js?1587:274 Error creating component filter=>agTextColumnFilter
Array.concat.ComponentResolver.newAgGridComponent # componentResolver.js?1587:274
Array.concat.ComponentResolver.createAgGridComponent # componentResolver.js?1587:236
Array.concat.FilterManager.createFilterInstance # filterManager.js?d1c0:376
Array.concat.FilterManager.createFilterWrapper # filterManager.js?d1c0:393
Array.concat.FilterManager.getOrCreateFilterWrapper # filterManager.js?d1c0:343
Array.concat.StandardMenuFactory.showPopup # standardMenu.js?505d:52
Array.concat.StandardMenuFactory.showMenuAfterButtonClick # standardMenu.js?505d:45
Array.concat.HeaderComp.showMenu # headerComp.js?f669:122
(anonymous) # headerComp.js?f669:107
filterManager.js?d1c0:401 Uncaught TypeError: Cannot read property 'then' of null
at FilterManager.Array.concat.FilterManager.putIntoGui (filterManager.js?d1c0:401)
at FilterManager.Array.concat.FilterManager.createFilterWrapper (filterManager.js?d1c0:394)
at FilterManager.Array.concat.FilterManager.getOrCreateFilterWrapper (filterManager.js?d1c0:343)
at StandardMenuFactory.Array.concat.StandardMenuFactory.showPopup (standardMenu.js?505d:52)
at StandardMenuFactory.Array.concat.StandardMenuFactory.showMenuAfterButtonClick (standardMenu.js?505d:45)
at HeaderComp.Array.concat.HeaderComp.showMenu (headerComp.js?f669:122)
at HTMLSpanElement.<anonymous> (headerComp.js?f669:107)
The refactoring work I did was to iterate over an array and create React-Bootstrap tab components that render the Ag-grid components when clicked. I place the array of tabs in a <div> to be rendered.
For my row data, it's an array like so:
[{
id: 1,
keyword: 'tv',
projects: [{ id: 1, name: 'Project 1' }, {id: 2, name: 'Project 2' }]
},
{
id: 2,
keyword: 'sofa',
projects: [{ id: 3, name: 'Project 3' }]
}]
My column definitions are returned from a function like this: (lookup is a hash where my filter options are stored, I iterate over the values and produce an array of strings to give to filterParams.values:
function createColumnDefs = (lookup) => ([
{
field: 'projects',
headerName: 'Projects',
filter: 'agSetColumnFilter',
cellRenderer: 'ListRenderer',
cellRendererParams: {
accessor: 'name'
},
filterParams: {
values: _.get(lookup, 'projects', []).map(project => project.name),
debounceMs: 200
}
},
{
field: 'keyword',
headerName: 'Keyword',
filter: 'agTextColumnFilter',
sort: 'asc',
filterParams: {
debounceMs: 200
},
pinned: 'left',
minWidth: 250
}
]);
Everything works fine including displaying rows, row selection, sorting, text filtering, the infinite scroll. ONLY when I click on the filter hamburger menu in the column header does it give the above error.
This filter has worked in the past and since then I have not altered row data structure or my column definitions or filter options.
*************** Screenshots for reference ***************
I solved this by
running npm i #ag-grid-enterprise/set-filter,
importing the module in the component that used the set filter: import { SetFilterModule } from '#ag-grid-enterprise/set-filter';
adding SetFilterModule to grid modules array:
gridModules = [ClientSideRowModelModule, RowGroupingModule, MenuModule, SetFilterModule];
and of course binding gridModules to the grid (which I had from before): <ag-grid-angular... [modules]="gridModules"></ag-grid-angular>
I got this solution from inspecting the code in the first example on https://www.ag-grid.com/javascript-grid-filter-set/
I just ran into the same issue and was able to resolve by removing "filter: true" from my column definitions. I see that you're defining specific types of filters in your definitions, you might try removing it and seeing if ag-grid recognizes the types of filters it needs. If that doesn't work, you might try changing those filters to custom filters instead. Hope that helps!

Viewmodel attribute 'links' cannot find the model type

While trying to execute the following code on show() we get an exception that the links attribute cannot find the model either if it is specified by class or if it is specified by entityName.
Ext.define('myapp.view.film.FilmsViewController', {
//extend: 'myapp.view.base.ViewController',
extend: 'Ext.app.ViewController',
alias: 'controller.films',
onAdd: function(button, event, options) {
this.createDialog(null)
},
createDialog: function(record) {
var me = this;
var view = me.getView(); //here is film panel
me.isEdit = !!record; //convert record to boolean
me.dialog = view.add({ //#3
xtype: 'filmwindow',
viewModel: { //#4
data: { //#5
title: record ? 'Edit: ' + record.get('title') : 'Add New Film',
},
links: { //#6
currentFilm: record || { //#7
//type: 'Film',
type: 'myapp.model.film.Film',
create: true
}
}
},
//session: true
});
me.dialog.show();
},
If we comment the links part of the code the rest is working ok.
Here is the interesting part of the exception:
[E] Ext.app.ViewModel.getRecord(): Invalid model name: myapp.model.film.Film
log # ext-all-rtl-debug.js?_dc=1446847440066:9121
Ext.apply.raise # ext-all-rtl-debug.js?_dc=1446847440066:2606
Ext.raise # ext-all-rtl-debug.js?_dc=1446847440066:2691
Ext.define.privates.getRecord # ext-all-rtl-debug.js?_dc=1446847440066:99865
Ext.define.linkTo # ext-all-rtl-debug.js?_dc=1446847440066:99748
Ext.define.privates.applyLinks # ext-all-rtl-debug.js?_dc=1446847440066:100120
If you dive into the source code you will find that the if statement that checks whether myapp.model.film.Film is a class fails..
After spending more than an entire day and using our wildest imagination we managed to figure out what is going on:
First of all check this link: https://www.sencha.com/forum/showthread.php?299699-Any-use-of-a-model-schema-breaks-Tree-model-even-if-not-extending.&p=1118964&viewfull=1#post1118964
You will find out that if you use more than one schema in your source code for no apparent reason these schemas conflict with each other and you are forced to provide a unique schema id.
Now this custom configuration should be propagated to all other configurations meaning that ViewModels will NOT work unless you specify the schema id that is going to be used.
In other words view model will only work if you add a schema like this:
viewModel: {
schema: "youruniqueschemaid",
data: {
title: record ? 'Edit: ' + record.get('title') : 'Add New Film',
},
links: {
currentFilm: record || {
//type: 'Film',
type: 'myapp.model.film.Film',
create: true
}
}
}
Yes the type attribute inside the links could not be more misleading!
You can also use the, shorter version, type: "Film" if you have set the entityName attribute inside the model as Film.
Refactor now
What Sencha should have done instead is force all developers to set the schema explicitly inside a ViewModel and use null if the model is not setup using a schema.
Of course as you can understand solving such an issue could not be done by diving into documentation nor diving inside the source code but rather using a wild guess of what kind of crazy conventions have been used.
In general the framework should be more explicit.

Second change listener in a Sencha Touch 2 view breaks build

I've got a Sencha Touch 2 view that's using this ratings class: Ext.ux.touch.rating, with two instances:
{
xtype: 'rating',
id: 'rating1',
value: -1,
itemCls: 'x-rating-star',
itemHoverCls: 'x-rating-star-hover',
listeners: {
change: function () {
Ext.getCmp('ratingBtn').setDisabled(Ext.getCmp('rating2').getValue() == -1)
}
}
},
...
{
xtype: 'rating',
id: 'rating2',
value: -1,
itemCls: 'x-rating-star',
itemHoverCls: 'x-rating-star-hover',
listeners: {
change: function () {
Ext.getCmp('ratingBtn').setDisabled(Ext.getCmp('rating1').getValue() == -1)
}
}
},
...
{
xtype: 'button',
ui: 'confirm',
text: 'Rate',
id: 'ratingBtn',
disabled: true
},
I'm trying, with the code above, to get ratingBtn (IDs are named slightly differently in my code) to be enabled once both ratings have been filled.
If I only have the first listener attached, things work fine (except no action on the second rating changing). If I attach the second listener with a console.log(this) or console.log(this.parent) or even Ext.getCmp('ratingBtn'), the app builds fine.
But if I attempt to invoke setDisabled() on the element (and this only happens for the second listener...and happens even if I call it as setDisabled(false)), I get this when compiling (plus a huge stack trace):
[ERROR] TypeError: 'undefined' is not an object
Stack trace:
file:////[snipped]/app/view/[snipped].js?_dc=1371009329838 : 346 : Anonymous
with line 346 being the line where I attempted to call setDisabled().
I can't find a way (including pushing both listeners to the controller) to get rid of this error, or one effectively identical to it. Even doing naughty things like document.getElementById return null, so the build tool says.
So, how do I fix this issue? I realize that the above code won't win any awards for OOP, but it should at least build...right?!? How do I get it to do that?

Categories