AngularJS view not getting updated with model changes - javascript

Controller (snippet, as its very large):
function loadImages() {
if (Authentication.loggedIn()) {
Images.get(function(s) {
$scope.images = s.images;
},
function(f) {} );
}
}
$scope.loginOnSubmit = function() {
Authentication.login($scope.model.login).then(
function(okResponse) {
WizardHandler.wizard().next();
loadImages()
},
function(failureResponse) {
// TODO: Alert use with the failure
}
);
};
loadImages();
View:
<wz-step title="{{ strings.images.bullet }}">
<div class="row">
<div class="col-md-10">
<h1 ng-bind="strings.images.title"></h1>
<p ng-bind="strings.images.description"></p>
<div ui-grid="{ data: images }" class="imagesGrid"></div>
</div>
</div>
</wz-step>
using angular-wizard wizard plugin (wz-step directive..).
I've looked over the web, thought its related to the $digest, etc.
I've tried using $timeout(...) to overcomes this, no go.
what happens is, the data doesnt show up in the view, but when I refresh the page, then its there, or when I even re-size the page, it appears.

Related

Vue data not updated but data changes

I'm getting crazy on this.
This is the code, is a component I'm using inside a form to show the preview of a video when I paste an url into an input:
<template>
<div class="row">
{{embedData}}
<input v-model="embedData" name="content[body]" id="content_body">
<div class="col-md-6">
<div class="form-group">
<div class="form-group url optional content_video_url form-group-valid">
<label for="content_video_url" class="url optional">Url del video</label>
<input #change="forceRerender" v-model="url" type="url" value="" name="content[video_url]" id="content_video_url" class="form-control is-valid string url optional">
</div>
</div>
</div>
<div class="col-md-6">
<div class="video-responsive"
<o-embed ref="embed" :url="url" :key="componentKey"></o-embed>
</div>
</div>
</div>
</template>
<script>
import oEmbed from './oEmbed'
import EventBus from '../utils/eventBus'
export default {
components: {
oEmbed
},
props: {
video_url: String,
video_caption: String
},
created: function() {
this.url = this.video_url;
this.caption = this.video_caption;
},
mounted: function() {
EventBus.$on('HTML', function (payLoad) {
this.embedData = payLoad
console.log('payLoad:' + this.embedData);
console.log('arrived');
});
},
data: function() {
return {
url: '',
caption: '',
componentKey: 0,
embedData: ''
}
},
methods: {
forceRerender () {
this.componentKey = this.componentKey + 1;
}
}
}
</script>
o-embed is a component, and I've added a simple bus emit function when the component is update:
mounted: function() {
EventBus.$on('HTML', function (payLoad) {
this.embedData = payLoad
console.log('payLoad:' + this.embedData);
});
}
If I check the console log I have this
payLoad: <iframe src="https://player.vimeo.com/video/596287904?app_id=122963&h=d77f5dc57c" width="426" height="240" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Raritan Bay Cruisers-Hopelawn New Jersey CruisebNight 8-31-2021.wmv"></iframe>
Everythink is working, this.embedData looks ok, I have the log, but when I render embedData in my view it's empty.
I give an additional info: I'm forcing the re-rendering of the embed component, but I don't think it's related.
Any ideas?
You're using an anonymous function.
this inside the anonymous function does not provide the component's context.
Try using an arrow function instead:
EventBus.$on('HTML', (payLoad) => {
this.embedData = payLoad
console.log('payLoad:' + this.embedData);
});
Mythos found the issue (at least one of them). The mustache template (double curly braces) interpret contents as plain text, not html. If you want to inject raw html into your page you should do something like
<div v-html="embedData"></div>
instead (https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML)

Laravel\Vue - ajax file upload not working on the production server

I have a component where I am uploading a video file, everything works fine on my local machine, and it used to work fine on the production server, Namechap is where I host the project, until only recently I have done some work and made changes, that I saw it doesn't work on the production server anymore.
I am using Vue v. 1.0.28, and this is the upload component, where in the fileInputChange() method I am posting form data, to the /upload endpoint, which on the production server for some reason I can't read in the backend:
<template>
<div class="card-content col-md-10 col-md-offset-1">
<div v-if="!uploading">
<div class="col-md-12 Image-input__input-wrapper">
Upload video
<input type="file" name="video" id="video" #change="fileInputChange" class="Image-input__input" accept="video/*">
</div>
</div>
<div class="alert alert-danger video-upload-alert" v-if="failed">Something went wrong. Please check the video format and try again. If you need any help please contact our <a>support service.</a></div>
<div id="video-form">
<div class="alert alert-info" v-if="uploading && !failed && !uploadingComplete">
Please do not navigate away from this page, until the video has finished uploading. Your video will be available at {{ $root.url }}/videos/{{ uid }}, once uploaded.
</div>
<div class="alert alert-success" v-if="uploading && !failed && uploadingComplete">
Upload complete. Video is now processing. Go to your videos.
</div>
<div class="progress" v-if="uploading && !failed && !uploadingComplete">
<div class="progress-bar" v-bind:style="{ width: fileProgress + '%' }"></div>
</div>
<div class="row">
<div class="col-md-12 form-group">
<label for="title" class="control-label">Title</label>
<input type="text" class="form-control" v-model="title">
</div>
<!--
<div class="col-md-12 form-group">
<label for="visibility" class="control-label">Visibility</label>
<select class="form-control" v-model="visibility">
<option value="private">Private</option>
<option value="unlisted">Unlisted</option>
<option value="public">Public</option>
</select>
</div>
-->
</div>
<div class="row">
<div class="col-md-12 form-group">
<label for="description" class="control-label">Description</label>
<textarea class="form-control" v-model="description"></textarea>
</div>
</div>
<div class="row">
<div class="col-md-12 form-group">
<button type="submit" class="btn btn-submit" #click.prevent="update">Save</button>
</div>
</div>
<div class="row">
<div class="col-md-12 form-group">
<span class="help-block pull-right">{{ saveStatus }}</span>
</div>
</div>
</div>
</template>
<script>
function initialState (){
return {
uid: null,
uploading: false,
uploadingComplete: false,
failed: false,
title: null,
link: null,
description: null,
visibility: 'private',
saveStatus: null,
fileProgress: 0
}
}
export default {
data: function (){
return initialState();
},
methods: {
fileInputChange() {
this.uploading = true;
this.failed = false;
this.file = document.getElementById('video').files[0];
var isVideo = this.isVideo(this.file.name.split('.').pop());
if (isVideo) {
this.store().then(() => {
var form = new FormData();
form.append('video', this.file);
form.append('uid', this.uid);
this.$http.post('/upload', form, {
progress: (e) => {
if (e.lengthComputable) {
this.updateProgress(e)
}
}
}).then(() => {
this.uploadingComplete = true
this.uploading = false
}, () => {
this.failed = true
this.uploading = false
});
}, () => {
this.failed = true
this.uploading = false
})
}
else {
this.failed = true
this.uploading = false
}
},
isVideo(extension) {
switch (extension.toLowerCase()) {
case 'm4v':
case 'avi':
case 'mpg':
case 'mp4':
case 'mp3':
case 'mov':
case 'wmv':
case 'flv':
return true;
}
return false;
},
store() {
return this.$http.post('/videos', {
title: this.title,
description: this.description,
visibility: this.visibility,
extension: this.file.name.split('.').pop()
}).then((response) => {
this.uid = response.json().data.uid;
});
},
update() {
this.saveStatus = 'Saving changes.';
return this.$http.put('/videos/' + this.uid, {
link: this.link,
title: this.title,
description: this.description,
visibility: this.visibility
}).then((response) => {
this.saveStatus = 'Changes saved.';
setTimeout(() => {
this.saveStatus = null
}, 3000)
}, () => {
this.saveStatus = 'Failed to save changes.';
});
},
updateProgress(e) {
e.percent = (e.loaded / e.total) * 100;
this.fileProgress = e.percent;
},
}
}
</script>
The problem is that on upload in my controller in the store function the request object is empty on the production server, which I got when I did dd($request->all()). Then it fails to find the video, in the network inspector I get a 404 error, which is returned by firstOrFail() method, because it can't find the Video model, since it is missing $request->uid.
No query results for model [App\Video].
This is the controller:
class VideoUploadController extends Controller
{
public function index()
{
return view('video.upload');
}
public function store(Request $request)
{
$player = $request->user()->player()->first();
$video = $player->videos()->where('uid', $request->uid)->firstOrFail();
$request->file('video')->move(storage_path() . '/uploads', $video->video_filename);
$this->dispatch(new UploadVideo(
$video->video_filename
));
return response()->json(null, 200);
}
}
I am not sure what is going on, since on inspecting the network tab in the console I am sending a request payload that looks like this:
------WebKitFormBoundarywNIkEqplUzfumo0A Content-Disposition: form-data; name="video"; filename="Football Match Play.mp4" Content-Type: video/mp4
------WebKitFormBoundarywNIkEqplUzfumo0A Content-Disposition: form-data; name="uid"
159920a7878cb2
------WebKitFormBoundarywNIkEqplUzfumo0A--
It is really frustrating since I have no idea how to fix this, when everything is fine on my local machine, not sure what is wrong on the production server and how to fix it?
Update
It started working again on its own, since I have created a ticket in the Namecheap support service, all of sudden after one day, it started working again, I haven't done any changes, and on asking the Namecheap support I have got an answer from them that they haven't done any changes either, so I have no idea what went wrong, which is still a bit frustrating since I would like to avoid that in the future, but at least everything is working now again as it should.
Laravel's $request->all() method only pulls from the input, thus in the store() method of VideoUploadController $request->all() return empty object.
In your script, it calls this.store() after checked the isVideo is true while file changes. As a result, there isn't a uid parameter or video parameter.

Vue.js + Require.js extending parent

I'm new to Vue.js but trying to get to grips with it. So far it has gone well and I've got quite far but I am stuck extending a parents template.
I am trying to make dashboard widgets that extend a default widget layout (in Boostrap). Please note that the below code is using Vue, Require, Underscore & Axios.
Parent file - _Global.vue
<template>
<div class="panel panel-default">
<div class="panel-heading">
<b>{{ widgetTitle }}</b>
<div class="pull-right">
<a href="#" v-on:click="toggleMinimized"
v-bind:title="(isMinimized ? 'Show widget' : 'Hide widget')">
<i class="fa fa-fw" v-bind:class="isMinimized ? 'fa-plus' : 'fa-minus'"></i>
</a>
</div>
</div>
<div class="panel-body" v-if="!isMinimized">
<div class="text-center text-muted" v-if="!isLoaded">
<i class="fa fa-spin fa-circle-o-notch"></i><br />
</div>
<parent v-if="isLoaded">
<!-- parent content should appear here when loaded -->
</parent>
</div>
</div>
</template>
<script>
export default {
// setup our widget props
props: {
'minimized': {
'default': false,
'required': false,
'type': Boolean
}
},
// define our data
data: function () {
return {
widgetTitle: 'Set widget title in data',
isLoaded: false,
isMinimized: this.$props.minimized
}
},
// when vue is mounted, open our widget
mounted: function () {
if(!this.isMinimized) {
this.opened();
}
},
// define our methods
methods: {
// store our widget state to database
storeWidgetState: function () {
// set our data to send
let data = {
'action' : 'toggleWidget',
'widget' : this.$options._componentTag,
'state' : !this.isMinimized
};
// post our data to our endpoint
axios.post(axios.endpoint, data);
},
// toggle our minimized data
toggleMinimized: function (e) {
// prevent default
e.preventDefault();
// toggle our minimized state
this.isMinimized = !this.isMinimized;
// trigger opened if we aren't minimized
if(!this.isMinimized) this.opened();
// save our widget state to database
this.storeWidgetState();
},
// triggered when opened from being minimized
opened: function () {
console.log('opened() method is where all widget logic should be placed');
}
}
}
</script>
Child file - Example.vue
Should extend _Global.vue using mixins and then display content within .panel-body
<template>
<div>
I want this content to appear inside the .panel-body div
{{ content }}
<img v-bind:src="image.src" v-bind:alt="image.alt"
v-if="image.src" class="img-responsive" style="margin: 0 auto" />
</div>
</template>
<script>
// import our widgets globals
import Global from './_Global.vue'
export default {
components: {
'parent': {
// what can I possibly put here??
}
},
// use our global mixin for all widgets
mixins: [Global],
// setup our methods for this widget
methods: {
opened: _.debounce(function () {
// make sure this can only be opened once
if(this.hasBeenOpened) return;
this.hasBeenOpened = true;
// temporarily allow axios to make external requests
let axiosHeaders = axios.defaults.headers.common;
let vm = this;
axios.defaults.headers.common = {};
axios.get('https://yesno.wtf/api')
.then(function (res) {
// set our content
vm.content = null;
// set our image content
vm.image.src = res.data.image;
vm.image.alt = res.data.answer;
})
.catch(function (err) {
// set our error text
vm.content = String(err);
})
.then(function () {
// this will always hit..
vm.isLoaded = true;
});
// restore our axios headers for security
axios.defaults.headers.common = axiosHeaders;
}, 300)
},
// additional data
data: function () {
return {
// set our widgets title
widgetTitle: 'Test title',
// logic for the specific widget
hasBeenOpened: false,
content: 'Loaded and ready to go...',
image: {
src: false,
alt: null
}
};
},
}
</script>
Currently my parent template is just completely overwriting my child view. The only way I can get it to work is by explicitly defining the template parameter inside components -> parent: {} but I don't want to have to do that...?
Ok, thanks to Gerardo Rosciano for pointing me the in right direction. I've used to slots to come up with an eventual solution. We then access parent methods and data attributes just to get everything working as it should.
Example.vue - our example widget
<template>
<div>
<widget-wrapper>
<span slot="header">Example widget</span>
<div slot="content">
<img v-bind:src="image.src" v-bind:alt="image.alt"
v-if="image.src" class="img-responsive" style="margin: 0 auto" />
{{ content }}
</div>
</widget-wrapper>
</div>
</template>
<script>
// import our widgets globals
import WidgetWrapper from './_Widget.vue'
export default {
// setup our components
components: {
'widget-wrapper': WidgetWrapper
},
// set our elements props
props: {
'minimized': {
'type': Boolean,
'default': false,
'required': false
}
},
// setup our methods for this widget
methods: {
loadContent: _.debounce(function () {
// make sure this can only be opened once
if(this.hasBeenOpened) return;
this.hasBeenOpened = true;
// temporarily allow axios to make external requests
let axiosHeaders = axios.defaults.headers.common;
let vm = this;
axios.defaults.headers.common = {};
axios.get('https://yesno.wtf/api')
.then(function (res) {
// set our content
vm.content = null;
// set our image content
vm.image.src = res.data.image;
vm.image.alt = res.data.answer;
})
.catch(function (err) {
// set our error text
vm.content = String(err);
})
.then(function () {
// this will always hit..
vm.isLoaded = true;
});
// restore our axios headers for security
axios.defaults.headers.common = axiosHeaders;
}, 300)
},
// additional data
data: function () {
return {
// global param for parent
isLoaded: false,
// logic for the specific widget
hasBeenOpened: false,
content: 'Loaded and ready to go...',
image: {
src: false,
alt: null
}
};
},
}
</script>
_Widget.vue - our base widget that gets extended
<template>
<div class="panel panel-default">
<div class="panel-heading">
<b><slot name="header">Slot header title</slot></b>
<div class="pull-right">
<a href="#" v-on:click="toggleMinimized"
v-bind:title="(minimized ? 'Show widget' : 'Hide widget')">
<i class="fa fa-fw" v-bind:class="minimized ? 'fa-plus' : 'fa-minus'"></i>
</a>
</div>
</div>
<div class="panel-body" v-if="!minimized">
<div class="text-center text-muted" v-if="!isLoaded">
<i class="fa fa-spin fa-circle-o-notch"></i><br />
Loading...
</div>
<div v-else>
<slot name="content"></slot>
</div>
</div>
</div>
</template>
<script>
export default {
// get loaded state from our parent
computed: {
isLoaded: function () {
return this.$parent.isLoaded;
}
},
// set our data element
data: function () {
return {
minimized: false
}
},
// when the widget is mounted, trigger open state
mounted: function () {
this.minimized = this.$parent.minimized;
if(!this.minimized) this.opened();
},
// methods to manipulate our widget
methods: {
// save our widget state to database
storeWidgetState: function () {
// set our data to send
let data = {
'action' : 'toggleWidget',
'widget' : this.$parent.$options._componentTag,
'state' : !this.minimized
};
// post this data to our endpoint
axios.post(axios.endpoint, data);
},
// toggle our minimized state
toggleMinimized: function (e) {
// prevent default
e.preventDefault();
// toggle our minimized state
this.minimized = !this.minimized;
// trigger opened if we aren't minimized
if(!this.minimized) this.opened();
// save our widget state to database
this.storeWidgetState();
},
// when widget is opened, load content
opened: function () {
// make sure we have a valid loadContent method
if(typeof this.$parent.loadContent === "function") {
this.$parent.loadContent();
} else {
console.log('You need to define a loadContent() method on the widget');
}
}
}
}
</script>

Child outlet goes empty when I refresh the url with id from {{link-to}} in Emberjs

I have a weird issue, the child outlet goes empty whenever I will refresh the page with the id. I have a list generated by {{link-to}} helper.
<script type="text/x-handlebars" id="twod">
<div class="row">
<div class="span4">
<img src="/img/2DPipeline.jpg" />
</div>
<div class="span3">
<h4>People with Roles</h4>
<div class="row">
<div class="span2">
<ul>
{{#each item in model}}
<li>{{#link-to 'twoduser' item}}{{item.firstname}} {{/link-to}}</li>
{{/each}}
</ul>
</div>
<div class="row">
<div class="span">
{{outlet}}
</div>
</div>
</div>
</div>
</script>
Here's the twoduser template,
<script type="text/x-handlebars" data-template-name="twoduser">
<div class="row">
<div class="span3">
Full Name: {{firstname}}{{lastname}}
EMail: {{email}}
</div>
</div>
</script>
App.js,
App.Router.map(function() {
this.resource('twod', function() {
this.resource('twoduser', {
path : ':user_id'
});
});
this.resource('threed');
});
App.TwoduserRoute = Ember.Route.extend({
model : function(params) {
return App.Twod.findBy(params.user_id);
}
});
App.Twod.reopenClass({
findAll : function() {
return new Ember.RSVP.Promise(function(resolve, reject) {
$.getJSON("http://pioneerdev.us/users/index", function(data) {
var result = data.users.map(function(row) {
return App.Twod.create(row);
});
resolve(result);
}).fail(reject);
});
},
findBy : function(user_id) {
var user = App.Twod.create();
$.getJSON("http://ankur.local/users/byId/" + user_id, function(data) {
user.setProperties(data.user);
});
user.set("user_id", user_id);
return user;
}
});
App.TwodRoute = Ember.Route.extend({
model : function() {
return App.Twod.findAll();
}
});
Selecting each one individually works fine and fills the child outlet, but when I refresh it, it goes blank.
Any ideas what might be causing the issue?
I can see two possible problems.
The first is that your URLs are different between findAll and findBy. Was that intentional?
The second is that findAll returns an Ember promise (Ember.RSVP.Promise), but findBy does not.
[UPDATE] : Based on the JSBin in the comments : http://jsbin.com/iPUxuJU/1/
The problem here is that the API endpoint is returning an array in the user response. It currently looks like this:
{user : [{ ... }] }
Ideally it would look like this :
{user : {....} }
You could change the API endpoint, or you could update your code to pull the first element from that array. Instead of :
user.setProperties(data.user);
You could do :
user.setProperties(data.user[0]);
Here's an altered JSBin : http://jsbin.com/oquBoMA/1#/twod/2

How to bind data from two tables in PhoneJs?

I have two tables:
nom_articole { id(PK), denumire, nom_um_id(FK) }
nom_um { id(PK), simbol, denumire }
I want to display:
nom_articole.id
nom_articole.denumire
nom_um.simbol
My html code:
<div data-options="dxView : { name: 'nom_articoleDetails', title: 'Nom_articole' } " >
<div data-options="dxContent : { targetPlaceholder: 'content' } " >
<div data-bind="dxScrollView: { }">
<h2 data-bind="text: nom_articole.denumire"></h2>
<div class="dx-fieldset">
<div class="dx-field">
<div class="dx-field-label">ID</div>
<div class="dx-field-value" data-bind="text: nom_articole.id"></div>
</div>
<div class="dx-field">
<div class="dx-field-label">Denumire</div>
<div class="dx-field-value" data-bind="text: nom_articole.denumire"></div>
</div>
<div class="dx-field">
<div class="dx-field-label">U.M.</div>
<div class="dx-field-value" data-bind="text: ????????????????"></div>
</div>
</div>
<div data-options="dxContentPlaceholder : { name: 'view-footer', transition: 'none' } " ></div>
</div>
</div>
My Javascrip code:
MobileApplication.nom_articoleDetails = function(params) {
return {
id: params.id,
//nom_um: new MobileApplication.nom_umViewModel(),
nom_articole: new MobileApplication.nom_articoleViewModel(),
handleDelete: function() {
DevExpress.ui.dialog.confirm("Are you sure you want to delete this item?", "Delete item").then($.proxy(function (result) {
if (result)
this.handleConfirmDelete();
}, this));
},
handleConfirmDelete: function() {
MobileApplication.db.nom_articole.remove(params.id).done(function() {
MobileApplication.app.navigate("nom_articole", { target: "back" });
});
},
viewShown: function() {
nom_articoleDetails = this;
MobileApplication.db.nom_articole.byKey(params.id).done(function(data) {
nom_articoleDetails.nom_articole.fromJS(data);
});
}
};
This code was generated by Devexpress multi-channel application wizard.
From the information you gave, and provided that nom_articole and nom_um share the same key, the code would be:
viewShown: function() {
// ... your code ...
MobileApplication.db.nom_um.byKey(params.id).done(function(data) {
nom_articoleDetails.nom_um.fromJS(data);
});
}
You uncomment the nom_um member and use text: nom_um.simbol as the binding text in the view.
Update:
To load an object by foreign key, you have two options. The first is cascading fetches:
MobileApplication.db.nom_articole.byKey(19).done(function (data) {
nom_articoleDetails.nom_articole.fromJS(data);
MobileApplication.db.nom_um.byKey(data.nom_um_id).done(function(data) {
nom_articoleDetails.nom_um.fromJS(data);
});
});
The second will work if your data service is properly configured OData. In this case you may use the expand feature:
MobileApplication.db.nom_articole.byKey(19, { expand: "nom_um" }).done(function (data) {
// data will contain a nested object
});
P.S. DevExpress provides Support service, and in case you cannot find the right answer here, you can ask them and share the solution.

Categories

Resources