Making a switch statement on my partials angularjs - angularjs

I'm having a problem, i'm unable to get my ng-switch to work on my partials. What I'm trying to do is upload an image but before I upload it I must first check if the included image size doesn't reach 25kb.
Here is my controller code:
$scope.validateAvatar = function(files) {
var fd = new FormData();
$scope.filesize = files[0].size;
$scope.filemaxsize = 25;
//Take the first selected file
fd.append("file", files[0]);
$scope.uploadAvatar = function() {
Api.uploadAvatar($scope.main.user.email, fd)
.then(function(result) {
console.log(result.data);
}, function(result) {
console.log(result);
})
};
};
and my partials code:
<form data-ng-submit="uploadAvatar()">
<input type="file" name="file" onchange="angular.element(this).scope().validateAvatar(this.files)"/>
<div ng-switch on="filesize / 1024 < filemaxsize">
<div ng-switch-when="true">
<input type="submit" value="Upload Avatar">
</div>
<div ng-switch-default>
Please choose you avatar.
</div>
</div>
</form>
Also do you think my validation is enough when checking for the image file size, say what if the image included is size:20MB, will my validation still catch it? Sorry in the first place I haven't been able to make it work the switch statements first . :(

You need to call $scope.$apply() after you changed $scope.filesize manually.
BTW, why not just let $scope.filemaxsize = 25 * 1024;

Related

How to reset/clear file Input

I am stuck with this problem from resetting an image file from input type=file. This is the scenario,
I set an image and then I clicked the 'Cancel' button (which means it was reset), and then I will set again the same image, it will not set. I do not know why but I think it is a bug.
Here is my code for resetting the image/form.
resetImage() {
this.$refs.addImageForm.reset()
this.dialog = ''
this.imgSrc = ''
this.fileName = ''
this.imgUrl = ''
this.file = ''
}
I am using Vue.js and Vuetify if that helps. I hope you can help me. I am stuck with this problem
HERE IS THE HTML
<template>
<v-dialog
persistent
v-model="dialog"
width="600"
>
<template v-slot:activator="{ on }">
<v-btn depressed color="primary" v-on="on">
<v-icon class="pr-2">check</v-icon>Approve
</v-btn>
</template>
<v-card>
<div class="px-4 pt-3">
<span class="subheading font-weight-bold">Approve Details</span>
<input
ref="image"
type="file"
name="image"
accept="image/*"
style="display: none;"
#change="setImage"
/>
<v-layout row wrap align-center>
<v-flex xs12 class="pa-0">
<div class="text-xs-center">
<v-img :src="imgUrl" contain/>
</div>
<VueCropper
:dragMode="'none'"
:viewMode="1"
:autoCrop="false"
:zoomOnWheel="false"
:background="false"
:src="imgSrc"
v-show="false"
ref="cropper"
/>
<v-form ref="addImageForm" lazy-validation>
<v-layout row wrap class="pt-2">
<v-flex xs12>
<v-text-field
outline
readonly
:label="imgSrc ? 'Click here to change the image' : 'Click here to upload image'"
append-icon='attach_file'
:rules="imageRule"
v-model='fileName'
#click='launchFilePicker'
></v-text-field>
</v-flex>
</v-layout>
</v-form>
</v-flex>
</v-layout>
</div>
<v-divider></v-divider>
<v-card-actions class="px-4">
<v-btn
large
flat
#click="resetImage()"
>Cancel</v-btn>
<v-spacer></v-spacer>
<v-btn
large
depressed
color="primary"
#click="approveCashout"
:loading="isUploading"
>Approve</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
You can use ref to reset the file uploader value.
this.$refs.fileupload.value = null;
codepen - https://codepen.io/Pratik__007/pen/MWYVjqP?editors=1010
To reset the input, I let vue rerender it. Just add a key to the input and change the value of the key whenever you want the file input to be cleared.
Like so:
window.app = new Vue({
el: '#app',
data: {
fileInputKey: 0
},
methods:{
inputChange() {
console.log('files chosen');
},
clear() {
this.fileInputKey++;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="file" #change="inputChange($event)" :key="fileInputKey"/>
<button #click="clear">Clear</button>
</div>
I tried several suggestions I found on Stackoverflow, but in my project there were several errors.
What solved my problem was:
<input type="file" ref="inputFile"/>
this.$refs.inputFile.reset();
This code above resets the field values.
I also came to this problem and could not reset the value. after going through the code of all previous projects and modifying them I got a lot of methods through which a file input could be reset.
one of the way is do is to capture the event object if you want to perform it after handling some code. another way is to change the type of the input element and change it back again.
<div id="app">
<input type="file" #change="onFilePicked" ref="file">
<button #click="clear()">Cancel</button>
</div>
var v = new Vue({
el:'#app',
data:{},
methods:{
clear() {
this.$refs.file.type='text';
this.$refs.file.type='file';
},
onFilePicked(event){
//if you directly want to clear the file input after handling
//some code........
event.target.value=null;
//OR
event.target.value='';
}
},
});
For Composition api
<input type="file"
class="custom-file-input"
id="customFileLang"
lang="en"
accept="image/*"
:class="{ 'is-invalid': errors && errors.images }"
#change="previewImg" multiple
>
Inside setup function:
const imgInput = ref(null) // for input type file
const previewImg = (event) => {
imgInput.value = event
// rest of code to preview img
}
const uploadImage = () => {
//on success
imgInput.value.target.value = null //reset input type file
}
I try mutilpe ways on vue, the best way is:
define this method:
removePic(inp) {
if (this.$refs[inp].files.length === 0) return
this.$refs[inp].files = []
delete this.body[inp]
this.$refs[`${inp}_preview`].src = ''
},
in the template use as this:
<b-form-file
ref="pic"
name="pic"
accept="image/jpeg, image/png, image/gif"
/>
<feather-icon
icon="XIcon"
size="18"
class="text-primary stroke-current"
#click="removePic('pic')"
/>
<div>
<img ref="pic_preview" src="#" alt="select" />
</div>

How to add a variable element into the url in AngularJS $http

I have the below code to pull the weather forecast. How do I make the zip code within the url as variable. I have done this in simple javascript by breaking down the url to substrings and then passing then in the get method but that is not working in AngularJS. Please help.
JS code
controllers.weatherCtrl= function ($scope,$http) {
$scope.getWeather=function() {
$http.get('http://api.openweathermap.org/data/2.5/forecast?zip=60007&appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
.then(function(response){
$scope.weatherdata=response.data;
});
};
};
Index.html
<div class="container border">
<input ng-model="zip">
<button class="btn" ng-click="getWeather()">Get Weather</button>
<br>
<span>{{weatherdata.city.name + ', ' + weatherdata.city.country}}</span>
</div>
You would need to add in a parameter to the weatherCtrl function and add that to variable to the URL. Then you call the function with the parameter.
JS code
controllers.weatherCtrl= function ($scope,$http) {
$scope.getWeather=function(zipcode) {
$http.get('http://api.openweathermap.org/data/2.5/forecast?zip='+zipcode+'&appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
.then(function(response){
$scope.weatherdata=response.data;
});
};
};
Index.html
<div class="container border">
<input ng-model="zip">
<button class="btn" ng-click="getWeather(zip)">Get Weather</button>
<br>
<span>{{weatherdata.city.name + ', ' + weatherdata.city.country}}</span>
</div>
If you create the url, then Mark S's answer is the correct one. if you receive the url from somewhere and you have to parse it and extract the zip code, you can use a regex match
url.match(/(?<=zip\=)\d*(?=\&)/g)
being url the url string.

Angular NG-Model not setting

I am trying to set the NG-Model on an input box (within a form if that matters) but it doesn't seem like it ever gets set on $scope. Everytime I set a breakpoint on the if statement in the controller 'lpScan' is always blank. I've tried to display the {{lpScan}} on screen and it also never seems like it sets there. Anybody have any ideas on why that might be?
Here is the small piece of controller code:
$scope.submitLP = function () {
$scope.lpScan = "";
if (!$scope.checkInForm.$valid) {
$scope.formValidate = 1;
return;
}
if ($scope.scanRequired && $scope.lpScan !== $scope.lp.LPNumber) {
FoundationApi.publish('load-notification',
{
title: 'Invalid LP',
content: 'Must scan current LP to receive it.',
autoclose: '4000'
});
}
and here is the html
<div class="full-block">
<form name="checkInForm">
<div class="center data-item">
<div class="button" ng-click="reprintLP()">Reprint LP</div>
</div>
<div class="data-item" ng-if="scanRequired && !lp.CheckedIn"
</div>
<div class="data-label-narrow">Scan LP:</div>
<div class="data-wide"><input id="assignLP" autocomplete="off" type="tel"
ng-keypress="processKeystroke(event)"
ng-model="lpScan" placeholder="Scan LP" name="LPNumber"
required ng-pattern="/^\d+$/" ng-minlength="20" ng-maxlength="20"
ng-trim="true"/>
<div class="data-error"
ng-if="(checkInForm.LPNumber.$dirty || formValidate === 1) && checkInForm.LPNumber.$invalid">
LPNumber must be 20 digits
</div>
</div>
</div>
</form>
First of all you have a broken div in your example code HTML.
<div class="data-item" ng-if="scanRequired && !lp.CheckedIn"
Try adding ng-change on your input something like ng-change="watchInput()" then in your controller add
$scope.watchInput = function() {
console.log($scope.lpScan);
}
Check your console log and see if you are getting a logging at all. If it is then just place your actionable code inside that function.
Looks like you are resetting your $scope.lpScan variable to blank everytime your submitLP function is fired, so declare it outside your submit function:
$scope.lpScan = "";
$scope.submitLP = function () {...
Here is an example:
https://plnkr.co/edit/jcLsGoVFCXkmv1SnUdHl?p=preview

access an element inside ng-repeat when dynamic html loaded

I am trying to access an DOM element inside a dymanic loaded HTML with http get request. The code that I am using inside controller is
$http.get("/ProjectManager/Edit?id=" + requestId).success(function (data, status, headers, config) {
data = data.trim();
var newDirective = angular.element(data);
angular.element(document.getElementById("editDiv")).html(newDirective);
$compile(newDirective)($scope);
var resources = angular.element(document.getElementById("projectResources")).val();
for (var i = 0; i < resources.length; i++) {
var resourceData = new ProjectResourcesModel(resources[i].ResourceID, resources[i].ProjectResourceID, resources[i].Employee, resources[i].IsApprover, resources[i].StartDate,
resources[i].EndDate)
$scope.resource.push(resourceData);
//$scope.$apply();
var id = "startDate" + resources[i].ResourceID;
angular.element(document.getElementById(id)).datetimepicker({
defaultDate: resources[i].StartDate,
format: 'MM/DD/YYYY',
})
}
})
I am trying to access a element with particular id that is present in my array element.
View HTML inside a ng-repeat is as follows
<div>
<div class="form-group">
<div class='input-group date' id='startDate{{item.ResourceID}}'>
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
<input ng-model="item.StartDate" type='text' id="txtStartDate{{item.ResourceID}}" class="form-control" />
</div>
</div>
</div>
</div>
I have to attach bootstrap datetimepicker to a textbox so I want to access a div inside ng-repeat whose ID is present inside by ng-repeat array.
But when I access the item with that id inside success of get request I am not getting the element. for e.g id of div would be startDate151 after the view binding.
So I tried using $scope.$apply() with which I am able attach the datepicker to element inside ng-repeat but I started getting a console error
Error: [$rootScope:inprog] $digest already in progress
Can anyone help me to resolve this or can I use some other alternative in this situation.

ngRepeat not updating after model changed

I'm tring to code a little search input to get data from a database using ngResource.
the data are shown in the page with a ng-repeat, but when i do the search and the $scope has been updated, the view is not updated and show old data.
Here is the code:
main.html (active view)
<div ng-controller="searchCtrl as searchCtrl" layout="column">
<form class="form-inline search-form col-md-offset-1">
<div class="form-group col-md-5">
<label class="sr-only" for="search_location">Location</label> <input
id="search_location" type="search" class="form-control"
ng-Autocomplete ng-model="place" placeholder="Location" />
</div>
<div class="form-group col-md-5">
<label class="sr-only" for="search_tags">Tags</label> <input
style="width: 100%;" id="search_tags" type="search"
class="form-control" id="search_tags" placeholder="Tags">
</div>
<div class="col-md-1">
<md-button class="md-fab md-mini" aria-label="Search" ng-click="searchCtrl.search()"> <md-icon class="md-fab-center"
md-font-icon="glyphicon glyphicon-search" style="color: black;"></md-icon>
</md-button>
</div>
</form>
</div>
<div ng-controller="mainCtrl">
<div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>
</div>
main.js
'use strict';
app.factory('Eventi', function($resource) {
return $resource('/eventsws/events/:location', {location : '#location'}, {
search: {
method: 'GET',
params: {
'location' : "#location"
},
isArray : true
}
})
});
app.controller('mainCtrl', function($scope, Eventi) {
$scope.eventi = Eventi.query();
});
searchbar.js
'use strict';
app.controller('searchCtrl', function($scope, Eventi) {
$scope.place = null;
this.search = function() {
$scope.eventi = Eventi.search({
'location' : $scope.place
});
}
});
when it start it get all the data from the database and display them correctly, when i try to make a search, the $scope.eventi is updated (i can see the new data in $scope.eventi from the debug) but the view still show the old data and never update.
I've tried to use $scope.$apply at the end of the search function but the result is the same.
Have you any idea why it's not working?
Thanks for your time.
The $scope.eventi you see in the debug is the one in your searchCtrl and not the one from your mainCtrl. To update your mainCtrl $scope.eventi you have to find an other way.
A clean but long solution would be using services to shares variables in your controllers.
To answer the question in comments :
i can see it updated, but the view still show the old data
I guess what's the problem (even if i actually didn't see your code).
Problem
If you bind your var like this :
Service
[...]
service.serviceVar = 1;
return service
[...]
This will create a "1" var with a reference.
Controller
[...]
$scope.myvar = Service.serviceVar;
[...]
This will bind $scope.myvar to the "1" reference.
If you do this in your service or in an other controller :
service.serviceVar = 2;
You will create a new var "2" with a new reference and you will assign this reference to service.serviceVar. Badly all your old references to the old 1 var will not update.
Solution
To avoid that do it like this :
Service
[...]
service.servicevar = {};
service.servicevar.value = 1;
return service
[...]
You create an object with a new reference and assign it to servicevar.
You create a var "1" and assign it to servicevar.value.
Controller
[...]
$scope.myvar = Service.servicevar;
[...]
You assign the servicevar reference to your scope var.
view
{{myvar.value}}
You can use the value by using the property of your var.
Updating the var doing this :
service.servicevar.value = 2;
You will create a new var "2" with a new reference and replace the old reference by this one.
BUT this time you keep all your references to servicevar in your controllers.
I hope i was clear and it answer your question.
EDIT :
Try to never ever use $scope.$apply. It's a really bad practice. If you use that to make something works, you should probably find an other to do that (And it will be a great question for Stacks i guess : "Why do i need $apply to solve my problem XXXXX")
rsnorman15 has a good point about your uses of asynchronous calls. Take a look at his answer too.
Here is one of my old plunker using a service to share properties
Just change:
$scope.eventi = Eventi.search({
'location' : $scope.place
});
to
Eventi.search({
'location' : $scope.place
}, function(eventi) {
$scope.eventi = eventi
});
It's an asynchronous call so it must be assigned in the success handler.
Another issue you are running into is your ng-repeat is not contained within the div that searchCtrl is scoped. Update your HTML so that it is contained like so:
<div ng-controller="searchCtrl as searchCtrl" layout="column">
<form class="form-inline search-form col-md-offset-1">
... form stuff
</form>
<div ng-repeat="evento in eventi" ng-include="'views/components/event_card.html'" class="col-md-3"></div>
</div>

Resources