How to instantiate a variable in Nuxt - html

I've tried a couple of different ways to instantiate a variable in Nuxt but neither way seems to work. I have read around the subject and suspect that perhaps what I'm trying to do is not compatible with Webpack but I'm not sure how.
Here is a jsFiddle of the code: jsfiddle.net/tutmoses/z2365g49/4
First in the script section I export dataSize:
<script>
export default {
data(){
return {
page_name: "Run Model",
dataSize: 1296
}
}
</script>
Then in the HTML above I'm trying to import it but nothing renders:
<div class="setting">
<span class="setting-label">Training Size:</span>
<input id="trainingSize" :value="dataSize"></input>
</div>
I've also tried this:
<div class="setting">
<span class="setting-label">Training Size:</span>
<input id="trainingSize" :value= {{ dataSize }}></input>
</div>
...but the value instantiates as
{{
I've tried both of the above options without binding the value but that didn't work either.
Another way I've tried is this in a separate file:
export const nnSettings = {
dataSize: 1296
}
And then importing it with this:
import nnSettings from '~/components/testindex.js'
Again, zip.
The reason why I'm importing the value is because other values will be calculated from it. What would be the standard, best way to do it?

Nuxt (Vue) uses v-model to bind to form input. Have a look here for more info on form bindings
<div class="setting">
<span class="setting-label">Training Size:</span>
<input id="trainingSize" v-model="dataSize"></input>
</div>

Related

document.querySelector causing errors on other methods when called

My apologies for the stupid question, but I am trying to change the name of a button upon uploading a file. My code to change it is this, via TypeScript:
const i = (document.querySelector('label') as any).innerText = filename;
The code above, inside the fileName method, changes the "Upload Project File" text into the name of whatever file that is uploaded.
<div class="row">
<div class="clg6 cmd8 csm10 cxs12" v-if="this.projectFile">
<button
class="button primary outline medium upload">
<label>
<input
type="file"
name="projectFile"
id="fileName"
accept=".xls, .xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
v-on:change="validateFileType(); hashContentMD5(); fileName; getPresignedURL()"/>
<i class="fas fa-cloud-upload"></i>
Upload Project File
</label>
</button>
</div>
</div>
And it works. However, upon change, it brings up errors in my other methods when they're called, such as this:
const file = (document.getElementById('fileName')as any).files[0]
The error that shows up is
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'files')
Removing the document.querySelector removes the error. This is the first time that I've encountered this. How can I fix it?
Problems:
You put your input inside the label tag. I learned this is okay.
Why using a button outside the whole label and input tags? I don't understand what your intention was with that.
You replace the inside of the label tag by a text node (containing the file name). Through your replacement you delete your input field out of the DOM. See querySelector line in your code.
After having replaced the input field, there is no fileName on the page anymore, so it getElementById results in null.
Solution:
(optionally) I'd delete the button tag and only keep the inside of it.
Don't operate on that label and don't try to overwrite the value of a file input field
By not removing the input field anymore, you can access it and read out the file name
See my example here: https://stackblitz.com/edit/js-fdxxnf
You can try with ref:
new Vue({
el: '#demo',
data() {
return {
projectFile: true
}
},
methods: {
changeLbl() {
this.$refs.lab.innerText = 'filename'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div class="row">
<div class="clg6 cmd8 csm10 cxs12" v-if="projectFile">
<button
class="button primary outline medium upload">
<label ref="lab">
<input
type="file"
name="projectFile"
id="fileName"
accept=".xls, .xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel"
v-on:change="changeLbl"/>
<i class="fas fa-cloud-upload"></i>
Upload Project File
</label>
</button>
</div>
</div>
</div>

Unable to control html elements using form state

I am trying to create a form in angular
<form name="vm.mechanicalForm">
<div layout="column" layout-padding>
<div layout="row" layout-align="end center">
<md-button class="aq-btn md-accent" type="submit"
ng-show="vm.Auth.check({access: 'EDIT'})"
ng-click="vm.save()"
ng-disabled="vm.mechanicalForm.$invalid">
Save Button
</md-button>
</div>
<div>
<md-input-container class="md-block"
ng-if="vm.building.mainSourceOfCooling === 'CHILLERS'">
<label>Cooler</label>
<input name="numberOfChillers" class="form-control"
type="number"
ng-model="vm.building.numberOfChillers"
required min="0">
<div ng-messages="vm.mechanicalForm.numberOfChillers.$error"
ng-hide="vm.building.numberOfChillers">
<div ng-message="min">
<span class="red">Number of Chillers must be a positive number</span>
</div>
</div>
</md-input-container>
</div>
</div>
</form>
I cannot get any of the states connected to the form, for example vm.mechanicalForm.$invalid/$valid to work. I want to be able to disable my save button when there is a negative number of Coolers entered. Even though the error Number of chillers must be positive is displayed the save button still works. Additionally, I wanted to change the ng-hide on the ng-messages div to hide the div when the form is valid, but that seems to break functionality too. What can I do to correct this error? I have looked around on stack overflow and the answers I have seen seem to suggest I am using the form state correctly.
EDIT:
Here is my controller code:
namespace properties {
export class MechanicalCtrl {
constructor(
public Messages,
public building,
public BuildingService,
private allEnums,
private Auth
) {}
public save() {
this.BuildingService.updateBuilding(this.building)
.then(() => {
this.Messages.success('Successfully updated mechanical information');
})
.catch(() => {
this.Messages.error('Unable to update mechanical information');
});
}
}
angular
.module('properties')
.controller('MechanicalCtrl', MechanicalCtrl);
}
According to the answer here I should be able to reference vm.mechanicalForm in my MechanicalCtrl as this.mechanicalForm (unless I misunderstood that answer). Another thing I have noticed is that I am not able to do this. I had tried debugging this by trying to console.log properties on the form but it is returned as undefined if I do console.log(this.mechanicalForm). Have I done something wrong?
EDIT 2:
I am setting up my template and controller as
.state(...) {
templateUrl: 'my/template/url',
controller: 'MechanicalCtrl as vm',
...
}

AngularJS ng-modal do not return latest value from form input

I am still new towards AngularJS, I made a simple textarea to handle user input using angular model binding like below code (noted that my ng-app and ng-controller are being injected somewhere else but it is within the entire <div></div>):
HTML:
<div ng-controller="StatusCtrl">
//some other HTML
<div class="sPTabs-holder">
<tabset>
<tab heading="Status">
<div>
<form class="statusPost" enctype="multipart/form-data">
<div class="form-group no-margin">
<div class="col-md-12 col-sm-12 no-pad">
<textarea type="text" ng-model="inputStatus" class="statusPostBox" placeholder="what's new on your mind?"></textarea>
</div>
</div>
<div class="form-group no-margin">
<div class="col-md-12 col-sm-12 no-pad">
<button style="width: 12%;" ng-click="postStatus()" class="btn btn-primary btn-sm" type="button">Share</button>
</div>
</div>
</form>
</div>
</tab>
<tab heading="Image">Image</tab>
</tabset>
</div>
</div>
JS:
'use strict';
var Status = angular.module('Status',['ui.bootstrap','ngResource','ngSanitize'])
Status.controller('StatusCtrl', ['StatusService','$resource','$scope','$http', '$timeout', '$sce',
function StatusCtrl(StatusService, $resource, $scope, $http, $timeout, $sce) {
//Usable models
$scope.inputStatus;
//Html-bind
$scope.makeTrust = function(html){
return $sce.trustAsHtml(html);
}
$scope.postStatus = function(){
if ($scope.inputStatus == null){
console.log('Blank post alert');
alert('You cannot post with blank statuses!');
}else{
console.log($scope.inputStatus);
}
}
}]);
My problem is whenever I click on the submit button angular will always pop me with the empty input error even though I have input in the textarea. At first I thought that I made a mistake in my model binding so I have tried out to echo the value in html using {{inputStatus}}, things appeared as it was typed and also when I try to define a default value in $scope.inputStatus = 'default value', the console does indeed echoed 'default value', but the problem is it doesn't store anything that is being typed in the form. What have i done wrong in my code?
Noted that I am not so familiar on how to setup AngularJS in JSFiddle. I apologize in advance if you would like to see the working demo.
**Update 1 - I have narrow down the problem, apparently the problem only occur when I am using angular tabs by Angular Bootstrap. So what happen is if you revise the HTML code, there is this <tabset> section. When declaring the ng-controller after the <tabset> section and everything works like a charm but if you declare it before the <tabset> section, that is where everything mess up.
You should initialize $scope.inputStatus in your controller, otherwise it will pop out an alert windows if you haven't input anything in the textarea (which will initialize or update $scope.inputStatus).
So you change your controller to
$scope.inputStatus = "";
Then everything will work, here is a working demo.
update
If you are using <tabset>, then you are facing child scope problem. <tabset> will create a child scope inside your controller, which means, the scope bind to tabset is the child of scope bind to StatusCtrl.
There are two ways to fix this problem. The first one is accessing the parent scope directly by changing your ngModel to below
<textarea type="text" ng-model="$parent.inputStatus" class="statusPostBox" placeholder="what's new on your mind?"></textarea>
The second one is easier but may looks like a trick, use Dot notation like #lcycook mentioned. In your controller StatusCtrl, declare a dictionary called data
$scope.data = {
inputStatus: ""
};
Then you can access the inputStatus by data.inputStatus anywhere inside the controller scope and you don't need to care about the child scope.
While there is no direct evidence, I suspect your text area is masked inside a child scope. This is common for new AngularJS developers.
While you are learning which directive creates a child scope (e.g. ng-if, ng-repeat), you can avoid this problem with "Dot notation". Which is, wrapping the model inside an object.
You can do this by initializing your ng-model or at least the wrapper object in your controller.
$scope.data = {};
// OR
$scope.data = {inputStatus=''};
Then in your template
<textarea type="text" ng-model="data.inputStatus" class="statusPostBox" placeholder="what's new on your mind?"></textarea>
Process it in your controller by referring it as $scope.data.inputStatus.
Some people even argue you are doing it wrong if you don't do this for any ng-model, but I find thinking wrapper object name is hard so I still use "dotless" one if I know the there is no child scope.

HTML "First Time User" form best practice (Jade / Angular)

So I'm trying to implement the following form in my app.
This is a form which should appear the first time a user tries to create a task in our app. Now my question is, what is the best way to deal with something like this? I'm not a very good frontend-guy and this might be a trivial question, I'm sorry if it is - nevertheless, I don't know the answer to it.
I'm not that curious about components etc, those are ok but rather of the flow. How should the things be organized in the html/js. Do I create a separate button each time, should the elements be dynamically inserted somehow.. etc
Any help would be awesome, thanks!
You could use angular directives for this, dynamically showing them based on other values. This should get you in the right direction:
<label for="taskName">Task name:</label>
<input type="text" name="taskName"
ng-model="task.name" />
<div ng-show="currentStep > 1">
<label for="assigned">Assigned:</label>
<select>
<!-- options etc. -->
</select>
</div>
<div>
<button class="btn btn-default"
ng-click="nextStep()">{{ currentStep.nextText }}</button>
</div>
controller:
.controller("MyCtrl",
["$scope", function($scope) {
$scope.steps = [
{ number: 1, nextText: "Let's go!" },
{ number: 2, nextText: "Next, please" }
];
$scope.task = {};
$scope.currentIndex = 0;
$scope.currentStep = $scope.steps[$scope.currentIndex];
$scope.nextStep = function (){
$scope.currentIndex += 1;
$scope.currentStep = $scope.steps[$scope.currentIndex];
}
}]);
Angular has a built in directive for this kind of process, ngSwitch. Using it, you can define a series of steps, and change the display based on the value of the step you are on in the process.
<form ng-switch="wizardStep">
<div ng-switch-when="Step1">This is Step 1</div>
<div ng-switch-when="Step2">This is Step 2</div>
</form>

angularjs: dynamic html dependent on json data

I want to show the content of my json model in a dynamic way, depending on the provided json. I use ng-repeat to loop through my data and want to display a html template to fill with data dependent on the encountered data type.
JSON
{
"elements": [
{
"type": "input-text",
"desc": "Full Name"
},
{
"type": "input-checkbox",
"desc": "Accept Terms"
}
]
}
This should result in different html code, appropriate filled with the json content.
E.g.
<div><label>Full Name</label> <input type="text"></div>
<div><input type="checkbox"> <label>Accept Terms</label></div>
Right now what I do is to use an angularjs directive to create an element and add the json values to the right spot. e.g. element.html('<div><input type="checkbox"> <label>' + scope.item.desc + '</label></div>') That seems like the jquery way (or worse) to do it although I want to do it the 'right' angularjs way.
How can I use a different HTML template filled with content, dependent on the encountered JSON data?
PS: The above example is a simple one, the encountered data is far more complex than switching the position of the label and input field.
All you need to do is set the data on the scope, then use the ng-repeat directive in your HTML to output it:
Controller:
.controller('MyData', function ($scope) {
$scope.myModel = {
elements: [ { desc: .. }, .. ]
};
})
You would be using the $http service or some other appropriate method in this controller to populate myModel with data, but in the end the data needs to end up on the $scope object somehow. Then it's the template's job to display that data:
<div ng-controller="MyData">
<ul>
<li ng-repeat="element in myModel.elements">
{{ element.desc }}
</li>
</ul>
</div>
A simple solution seems to use ngSwitch with different HTML paths, e.g.:
<div ng-switch="item.type">
<div ng-switch-when="input-text">
<div><label>{{item.desc}}</label> <input type="text"></div>
</div>
<div ng-switch-when="input-checkbox">
<div><input type="checkbox"> <label>{{item.desc}}</label></div>
</div>
<div ng-switch-default>Unknown item.type: {{item.type}}</div>
</div>
Seems the approach using an angularjs directive (which I took first) may be a good solution for complex scenarios as "Huy Hoang Pham" points out in his blog post: http://onehungrymind.com/angularjs-dynamic-templates/ (thanks!)