Materialize: cannot read property 'badInput' of undefined - materialize

I'm using Behat with Zombie.js for end to end tests, using materializecss framework. I'm testing a case where a create action fails and the controller redirects back to the form page.
I get the following exception:
And I press "Crear" # WebContext::pressButton()
Error while processing event 'click': "TypeError: Cannot read property 'badInput' of undefined
at .<anonymous> (https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.4/js/materialize.min.js:8:22076)
at Function.each (https://code.jquery.com/jquery-2.1.1.min.js:2:2880)
at n.each (https://code.jquery.com/jquery-2.1.1.min.js:2:847)
at Object.Materialize.updateTextFields (https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.4/js/materialize.min.js:8:21969)
at HTMLDocument.<anonymous> (https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.4/js/materialize.min.js:8:22558)
at j (https://code.jquery.com/jquery-2.1.1.min.js:2:26860)
at Object.fireWith [as resolveWith] (https://code.jquery.com/jquery-2.1.1.min.js:2:27673)
at Function.ready (https://code.jquery.com/jquery-2.1.1.min.js:2:29467)
at HTMLDocument.I (https://code.jquery.com/jquery-2.1.1.min.js:2:29658)
at callListeners (/usr/lib/node_modules/zombie/node_modules/jsdom/lib/jsdom/events/EventTarget.js:170:34)
in http://localhost/myresource/create" (Behat\Mink\Exception\DriverException)
The worst part is that this doesn't happen on the actual browser (maybe it's cause of a redirection?) so I have no idea how to reproduce it.
Any ideas?

I am facing with the same issue with Zombie.js testing
describe('User visits test page', function() {
const browser = new Browser();
it('should open page ', function(done) {
browser.visit('/test', function() {
done();
});
})
});
of simple html page with one input:
<html>
<head>
<title>Test</title>
<link rel="stylesheet" href="/vendor/materialize/css/materialize.min.css" />
<script type="text/javascript" src="/vendor/jquery.min.js"></script>
<script type="text/javascript" src="/vendor/materialize/js/materialize.js"></script>
</head>
<body>
<label for="email">Email</label>
<input id="email" name="email" type="email" />
</body>
</html>
input.validity is undefined in this case. The root cause is not clear for me. But it can be avoided with materialize.js changing
$(input_selector).each(function(index, element) {
if ($(element).val().length > 0
|| element.autofocus
||$(this).attr('placeholder') !== undefined
|| $(element)[0].validity.badInput === true) {
$(this).siblings('label').addClass('active');
}
else {
$(this).siblings('label').removeClass('active');
}
});
to
if ($(element).val().length > 0
|| element.autofocus
|| $(this).attr('placeholder') !== undefined) {
$(this).siblings('label').addClass('active');
} else if ($(element)[0].validity) {
if ($(element)[0].validity.badInput === true) {
$(this).siblings('label').addClass('active');
}
else {
$(this).siblings('label').removeClass('active');
}
}
else {
$(this).siblings('label').removeClass('active');
}
I've created pull request to materialize. Here's a link to it.

Related

changing values in .vue file of Vue JS project not working

I have found a tool called XLSX to JSON on github, which has been made using vuejs/sheetjs. git repo, This tool is available online via an interface - but recently it seems to have broken and I cant download my converted json file.
Therefore my intention was to clone the repo, and change some bits around to fix it (just console json file instead of DL).
I haven't used Vue js before. After looking through the index and the origins of the functions I saw that the whole page seems to be reliant on this app.vue file. However - when editing the values and reloading the webpage - theres no change what so ever!
App.vue:
<template>
<div class="col">
<div class="row">
<div id="dropZone" v-on:drop.prevent="parseXLSX($event)" v-on:dragend="cleanup" ondragenter="event.preventDefault();" ondragover="event.preventDefault(); event.dataTransfer.dropEffect='copy'" class="col drop-box">
<h2 class="text-center"> Drag your xlsx file here.</h2>
</div>
</div>
<div class="row">
<input type='file' id='inputFile' v-on:change="parseXLSX($event.target.files)">
<div v-if="hasDownload">
<a id="download"> Download Localalization JSON </a>
</div>
</div>
<div class="row">
<div class="col json-box">
<h2 class="text-center"> JSON Output</h2>
<pre id="output"> </pre>
</div>
</div>
<xlsx-footer></xlsx-footer>
</div>
</template>
<script>
import Footer from './components/footer.vue';
export default {
data() {
return {
hasDownload: false,
}
},
methods: {
parseXLSX(event) {
const XLSX = window.XLSX;
let file = this.getFile(event);
let workBook = null;
let jsonData = null;
if(file !== null) {
const reader = new FileReader();
const rABS = true;
reader.onload = (event) => {
// I WANT TO do edits but nothing seems to work
//console logs not working etc...
const data = event.target.result;
if(rABS) {
workBook = XLSX.read(data, {type: 'binary'});
jsonData = workBook.SheetNames.reduce((initial, name) => {
const sheet = workBook.Sheets[name];
initial[name] = XLSX.utils.sheet_to_json(sheet);
return initial;
}, {});
const dataString = JSON.stringify(jsonData, 2, 2);
document.getElementById('output').innerHTML = dataString.slice(0, 300).concat("...");
this.setDownload(dataString);
}
}
if(rABS) reader.readAsBinaryString(file);
else reader.readAsArrayBuffer(file);
}
},
getFile(item) {
if(item.dataTransfer !== undefined) {
const dt = item.dataTransfer;
if(dt.items) {
if(dt.items[0].kind == 'file') {
return dt.items[0].getAsFile();
}
}
}
else {
return item[0];
}
},
setDownload(json) {
this.hasDownload = true;
setTimeout(()=> {
const el = document.getElementById("download");
el.href = `data:text/json;charset=utf-8,${encodeURIComponent(json)}`;
el.download = 'localization.json';
}, 1000)
},
cleanup(event) {
console.log("Cleaned up Event", event);
}
},
components: {
'xlsx-footer': Footer,
}
}
</script>
main.js:
'use strict';
var _vue = require('vue');
var _vue2 = _interopRequireDefault(_vue);
var _app = require('./app.vue');
var _app2 = _interopRequireDefault(_app);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var app = new _vue2.default({
el: "#app",
render: function render(h) {
return h(_app2.default);
}
});
index.html:
<!DOCTYPE html>
<html>
<head>
<title> XLSX-TO-JSON </title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/tether/1.4.0/tether.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.11.3/xlsx.full.min.js"></script>
<link rel="stylesheet" type="text/css" href="./css/style.css">
</head>
<body>
<h1 class="title text-center"> XLSX-TO-JSON </h1>
<div id="app" class="container">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"> </script>
<script src="bin/bundle.js"></script>
<!-- <script src="assets/bundle.js"></script> -->
</body>
</html>
All I want to do is edit the functions in the app.vue file!
Any help would be great, cheers!
Try to modify the package.json file by adding "prod":"webpack" in the "scripts" brackets. Running npm run prod should recreate your bundle.js file after .vue files modification using the webpack.config.js provided.
Also you could use script test using npm run test which launch webpack-dev-server and enable hot reload which is more convinient for dev purpose.
When you make change in any vue js file you have run npm run prod and you have to either upload the whole project in the server or upload the public folder in the server

How to include promises in vuejs methods

The code below has vuejs methods. One is calling another through the promise function. How can I make handleStart be invoked first, then once done is true, foo will be resolve, and handleStart will finish. The start button must be clicked first
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button
#click="handleStart"
>
START
</button>
<button
#click="done = true"
>DONE</button>
<h1>Start the app: {{start}}</h1>
<h1>Is it done? {{done}}</h1>
</div>
<script>
var app = new Vue({
el: '#app',
data () {
return {
start: false,
done:false
}
},
methods: {
foo() {
return new Promise( (resolve) => {
if (this.done) {
console.log("done is recorded")
resolve("Yaa")
}
})
},
handleStart () {
this.start = true
// how to make this an obsersable
this.foo()
.then( (data ) => console.log("I must be printed with:", data))
}
}
})
</script>
</body>
</html>
you need to use watchers to watch this.done change
watch: {
done(newVal, oldVal) {
if (newVal) {
// do something
}
}
},
methods: {
async handleStart () {
// how to make this async
this.start = true
const data = await this.foo()
console.log("I must be printed with:", data))
}
}
The problem is with the if (this.done) check.
When done is false, the promise is never resolved, and the handleStart never receives data.
If you need to react when a data has changed, take a look Vue's watchers

dgrid (onDemandGrid) loads on first time button click, but error on second time button is clicked

Thanks to some previous help here, I got the Dojo dgrid to work; and even figured out how to tie it to data from my rest service.
Now I added an input box, a button, and all the logic happens on the button-click. But the second time I click the button, even with the same input value in the input field, I get an error.
ERROR:
TypeError: Cannot read property 'element' of undefined in StoreMixin.js:33
Including the picture so you can see my console.logs
I read this How To reset the OnDemandGrid, but is it necessary to check to see if grid exists and do different logic? Can't I just "new up" a new one each time?
CODE:
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props='title:"CustomersGrid"'>
<label for="lastnameStartsWith">Lastname Starts With:</label>
<input id="lastnameStartsWith" type="text" name="lastnameStartsWith" value="Wag"
data-dojo-type="dijit/form/TextBox"
data-dojo-props="trim:true, propercase:true" />
<br />
<br />
<button id="queryStudentsButton" data-dojo-type="dijit/form/Button"
data-dojo-type="dijit/form/Button"
data-dojo-props="iconClass:'dijitIconTask'">
<span>Query</span>
<script type='dojo/on' data-dojo-event='click'>
require([
'dstore/RequestMemory',
'dstore/Memory',
'dgrid/OnDemandGrid'
], function (RequestMemory, Memory, OnDemandGrid) {
var url = '../students/' + dojo.byId('lastnameStartsWith').value;
console.log("query students for dataGrid latsnameStartsWith:" + dojo.byId('lastnameStartsWith').value);
require(['dojo/request'], function(request){
request.get(url,
{headers: {"Content-Type": 'application/json',
"username": securityConfig.username,
"password": securityConfig.password}}
)
.then(function(response){
//console.log("string response=" + response);
var respJSON = JSON.parse(response);
var respDataForDGrid = respJSON.recordset;
console.log("got respJSON back, num rows= " + respDataForDGrid.length);
//================================================
// Create an instance of OnDemandGrid referencing the store
console.log("Debug1");
var grid2 = new OnDemandGrid({
collection: new Memory({ data: respDataForDGrid }),
columns: {
student_id: 'ID',
student_firstname: 'First Name',
student_lastname: 'Last Name',
student_city: 'City',
student_state: 'State',
student_zip: 'Zip'
}
}, 'grid2');
console.log("Debug2");
grid2.startup();
console.log("Debug3");
},
function(error){
console.log("Error=" + error);
//dom.byId('studentFeedback').value += response;
});
});
});
</script>
</button>
<h2>My demoGrid - From JSON RestService (Database)</h2>
<div id='grid2'></div>
</div>
Part 2 -
I tried mix of your code and code on this page:
How To reset the OnDemandGrid
if (grid2Registered){
console.log("reuse existing grid");
grid2Registered.set('collection', memStore);
// refresh: clear the grid and re-queries the store for data.
grid2Registered.refresh();
}
else{...
Doc here (https://github.com/SitePen/dgrid/blob/v0.4.3/doc/components/core-components/OnDemandList-and-OnDemandGrid.md) says:
Clears the grid and re-queries the store for data. If
keepScrollPosition is true on either the instance or the options
passed to refresh, an attempt will be made to preserve the current
scroll position. OnDemandList returns a promise from refresh, which
resolves when items in view finish rendering. The promise resolves
with the QueryResults that were rendered.
This one has been tough! Below a working example.
First I switched from declarative to programmatic for the onClick function: declarative scripts are parsed by dojo, and as a consequence you cannot examine them (set break points, etc.) under the debugger (at least I don't know how to do that). So it seems to me good practice to avoid them.
Then, indeed the bug is due to re-instantiating the dgrid with the same id, so that you do need a way to detect that the dgrid already exists. But there is a trick: for dgrids to be properly handled by the dijit system, they need to be mixed in with the dijitRegistry extension. See here for details.
Then you can use registry.byId('grid2') to detect that the dgrid already exists.
Also I had to skip the respDataForDgrid part and used directly respJSON instead (may be due to a difference with your server side(?) - I used a simple text file with a json array on the server side).
<!DOCTYPE HTML><html lang="en">
<head>
<meta charset="utf-8">
<title>Neal Walters stask overflow test</title>
<link rel="stylesheet"
href="dojo-release-1.12.2-src/dijit/themes/claro/claro.css"
media="screen">
<link rel="stylesheet"
href="dojo-release-1.12.2-src/dgrid/css/dgrid.css" media="screen">
</head>
<body class="claro">
<div data-dojo-type="dijit/layout/ContentPane"
data-dojo-props='title:"CustomersGrid"'>
<label for="lastnameStartsWith">Lastname Starts With:</label> <input
id="lastnameStartsWith" type="text" name="lastnameStartsWith"
value="Wag" data-dojo-type="dijit/form/TextBox"
data-dojo-props="trim:true, propercase:true" /> <br /> <br />
<button id="queryStudentsButton" data-dojo-type="dijit/form/Button"
data-dojo-props="iconClass:'dijitIconTask', onClick: myClick">Query</button>
<h2>My demoGrid - From JSON RestService (Database)</h2>
<div id='grid2'></div>
</div>
<script src="dojo-release-1.12.2-src/dojo/dojo.js"
data-dojo-config="async:true"></script>
<script type="text/javascript">
require(["dojo", "dojo/parser", "dojo/domReady!"],
function(dojo, parser){
parser.parse();
});
function myClick(){
var url = 'students/' + dojo.byId('lastnameStartsWith').value, securityConfig = {username: 'john', password: 'Doe'};
console.log("query students for dataGrid latsnameStartsWith:" + dojo.byId('lastnameStartsWith').value);
require(['dojo/_base/declare', 'dojo/request', "dijit/registry", "dstore/RequestMemory", "dstore/Memory", "dgrid/OnDemandGrid", "dgrid/extensions/DijitRegistry"], function(declare, request, registry, RequestMemory, Memory, OnDemandGrid, DijitRegistry){
request.get(url,{})
.then(function(response){
console.log("string response=" + response);
var respJSON = JSON.parse(response);
//var respDataForDGrid = respJSON.recordset;
//console.log("got respJSON back, num rows= " + respDataForDGrid.length);
//================================================
// Create an instance of OnDemandGrid referencing the store
console.log("Debug1");
var theGrid = registry.byId('grid2');
if (theGrid){
theGrid.set('collection', new Memory({data: respJSON}));
}else{
var grid2 = new (declare([OnDemandGrid, DijitRegistry]))({
collection: new Memory({ data: respJSON }),
columns: {
student_id: 'ID',
student_firstname: 'First Name',
student_lastname: 'Last Name',
student_city: 'City',
student_state: 'State',
student_zip: 'Zip'
}
}, 'grid2');
console.log("Debug2");
grid2.startup();
console.log("Debug3");
}
},
function(error){
console.log("Error=" + error);
//dom.byId('studentFeedback').value += response;
});
});
};
</script>
</body>
</html>

How to get results after submit form with PhantomJS?

I'm trying to get results from a simple form using PhantomJS. I'm using jQuery but don't work. I have this HTML:
<!doctype html>
<html>
<head>
<title>PhantomJS!</title>
</head>
<body>
<form method="post" id="frm">
<input type="text" name="nombre" id="nombre" />
<input type="submit" value="Publicar" id="btn-submit" />
</form>
Your name is <span id="nombrez"><?php if (isset($_POST['nombre'])) { echo $_POST['nombre'];} ?></span>
</body>
</html>
And this Javascript code:
var page = require('webpage').create();
page.open('http://localhost/phantom/', function() {
page.includeJs("https://code.jquery.com/jquery-3.1.1.slim.js", function() {
page.evaluate(function() {
$('#nombre').val('Fabian');
document.forms[0].submit();
});
page.onLoadFinished = function(){
console.log($("#nombrez").html());
phantom.exit();
};
});
});
page.onLoadFinished must not be called inside of page.evaluate, but inside the main PhantomJS script:
var page = require('webpage').create();
page.onLoadFinished = function(){
var html = page.evaluate(function(){
return document.getElementById("nombrez").innerHTML;
});
console.log(html);
phantom.exit();
};
page.open('http://localhost/phantom/', function() {
page.includeJs("https://code.jquery.com/jquery-3.1.1.slim.js", function() {
page.evaluate(function() {
$('#nombre').val('Fabian');
document.forms[0].submit();
});
});
});
However page.onLoadFinished fires every time a page is done loading and with this implementation phantom will exit the first the time page is loaded, even before the form is submitted.
You need to implement some check to distinguish between the first and the second load of the page. For example, if return html variable is empty it means that we haven't submitted page yet.

VueJS Data ForLoop Issue

I'm using forloop to check the items in my data in COMPONENT.
{
data:function(){
return {
items:[
{id:1,name:'John'},
{id:2,name:'FooBz'}
]
}
}
}
now I want to check the value first in console in ready hook of my component.
{
.....
ready:function(){
console.log(this.items);
// this return a [__ob__: Observer]
this.items.forEach(function(x,y){
............
});
}
}
the this.items return a '[ob: Observer]' which I can't iterate through because the length of that value is 0 it supposed to be 2.
EDIT:
this is strange on my JSBIN all are working but in my real code its not. Even though I copied my logic from my real code I'm using Laravel Elixir to compile my javascript and 1.0.24 version of Vue.
http://jsbin.com/gijaniqero/edit?html,js,console,output
Your code should be okay.
Just using your code, i have made demo. It should be okay
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
<test_component></test_component>
</div>
<template id="test_component">
<div></div>
</template>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el:'#app',
data: {
},
components : {
'test_component' : {
template : '#test_component',
data:function(){
return {
items:[
{id:1,name:'John'},
{id:2,name:'FooBz'}
]
}
},
ready : function(){
this.items.forEach(function(x,y){
console.log( 'id is : ' + x.id);
console.log( 'name is L ' + x.name);
console.log( 'key is ' + y);
});
}
}
}
})
</script>
</body>
</html>