Hi I have a form in Angular, that i build with values from an Observable from API.
.subscribe((res) => {
this.data = res['attributes'];
});
//this.data is array of objects!!
this.attribs = modifyClean(this.data);
this.attribsOriginal = this.attribs;
Object.freeze(this.attribsOriginal);
After the form is built with this.attribs. If the user edits its original form values and Clicks save, the api saves it.
But if the API fails to save (500 error or something) I want the form to go back to its original values.
I am not using Reactive forms on purpose. But here is what i am doing when the api fails in error code
,error {
this.attribs = this.attribsOriginal;
}
But this is not replacing the form values with original values. It is retaining the values. I console.log both this.attribs and this.attribsOriginal in error block. Both of them are same values. How is this possible. I froze attribsOriginal.
If i say this.attribs = []; the form is completely removed as expected.
But why doesnt this.attribs = this.attribsOriginal, replace the form values with orginal values.
I thought freezing this.attribsOriginal will have no impact no matter what you do to this.attribs.
what can be done to avoid this situation?
It looks like this.attribs is a reference to data returned by modifyClean(this.data), and this.attribsOriginal is also a reference to the same data. If you're trying to clone an object this looks helpful
Angular uses change detection to decide when to build/rebuild the portion of the dom using your "this.attribs" data. Since nothing is changing it isn't building/rebuilding the dom.
I think you could try arbitrarily changing the data in the component.ts file, and changing it back, or this might be helpful
Related
So I'm having an issue with my create method in my angular. I'm using django for my backend, and I doublechecked, everything is working in the backend, with postman. Anyways here's the error. When I try to make a post request, this is the error that I get in the console. Below oyu may find the product that is sent from my end.
Note: This may not be the ideal approach to the overall problem, but it does answer the immediate question at hand.
As the error states you need to pass in an array (irrespective of how many categories are selected) rather than a string. Make the following change:
onSubmit() {
const formValues = Object.assign({}, this.productForm.value);
productForm["product_category"] = productForm["product_category"]
.split(',').map(e => e.trim());
}
Here, the product_category from formValues is fetched and the string is split based on , which results in an array - to which empty spaces are removed and assigned back as the new value to product_category.
I've form with some input fields, upon submit I make a $http call and populate a model object that binds data to a table on my view. Once user saw the result, they may change the data in the form and submit the same once again, I'm trying to clear the result and populate the data with the new result. Some time the result can be same, in such cases user is not able to understand whether the form was submitted and new results has been updated or not. I'm setting my model object to undefined expecting that the data on the table will get wiped. I also have an ng-if for null check of the object and control the display of the table, I expect it to hide the table, but unfortunately it is not happening. How can I do that? $scope.apply() is the only way for me to do that. I hate to use it as it causes full digest cycle. Please advise.
You can create a separate scope for clearing the data and call that using model on button click.
Example
$scope.clearData = function () {
$scope.ApplicationFormName = "";
$scope.FirstName="";
//put your logic for clearing the form here
};
in HTML
<button title="Clear" ng-click="clearData()"></button>
I am relatively new to Meteor, and I'm trying to create a web store for my sister-in-law that takes data from her existing Etsy store and puts a custom skin on it. I've defined all of my Meteor.methods to retrieve the data, and I've proofed the data with a series of console.log statements... So, the data is there, but it won't render on the screen. Here is an example of some of the code on the server side:
Meteor.methods({
...
'getShopSections': function() {
this.unblock();
var URL = baseURL + "/sections?api_key="+apiKey;
var response = Meteor.http.get(URL).data.results;
return response;
}
...
});
This method returns an array of Object. A sample bit of JSON string from one of the returned Objects from the array:
{
active_listing_count: 20,
rank: 2,
shop_section_id: 1******0,
title: "Example Title",
user_id: 2******7
}
After fetching this data without a hitch, I was ready to make the call from the client side, and I tried and failed in several different ways before a Google search landed me at this tutorial here: https://dzone.com/articles/integrating-external-apis-your
On the client side, I have a nav.js file with the following bit of code, adapted from the above tutorial:
Template.nav.rendered = function() {
Meteor.call('getShopSections', function(err, res) {
Session.set('sections', res);
return res;
});
};
Template.nav.helpers({
category: function() {
var sections = Session.get('sections');
return sections;
}
});
And a sample call from inside my nav.html template...
<ul>
{{#each category}}
<li>{{category.title}}</li>
{{/each}}
</ul>
So, there's a few things going on here that I'm unsure of. First and foremost, the DOM is not rendering any of the category.title String despite showing the appropriate number of li placeholders. Secondly, before I followed the above tutorial, I didn't define a Session variable. Considering that the list of shop categories should remain static once the template is loaded, I didn't think it was necessary from what I understand about Session variables... but for some reason this was the difference between the template displaying a single empty <li> tag versus a number of empty <li>'s equal to category.length --- so, even though I can't comprehend why the Session variable is needed in this instance, it did bring me one perceived step closer to my goal... I have tried a number of console.log statements on the client side, and I am 100% sure the data is defined and available, but when I check the source code in my Developer Tools window, the DOM just shows a number of empty li brackets.
Can any Meteor gurus explain why 1) the DOM is not rendering any of the titles, and 2) if the Session variable indeed necessary? Please let me know if more information is needed, and I'll be very happy to provide it. Thanks!
You set the data context when you use #each, so simply use:
<li>{{title}}</li>
If a Session is the right type of reactive variable to use here or not is hard to determine without knowing what you are doing but my rough guess is that a Mini Mongo collection may be better suited for what it appears you are doing.
To get you started on deciding the correct type of reactive variable to use for this head over to the full Meteor documentation and investigate: collections, sessions, and reactive vars.
Edit: To step back and clarify a bit, a Template helper is called a reactive computation. Reactive computations inside of helpers will only execute if they are used in their respective templates AND if you use a reactive variable inside of the computation. There are multiple types of reactive variable, each with their own attributes. Your code likely didn't work at all before you used Session because you were not using a reactive variable.
I'm still getting my feet wet with Angular, so keep that in mind as you read about my problem.
I have a series of dynamically generated checkboxes that can be used to grant permissions to other users. Whenever a checkbox is updated, it updates a $scope.permissions array that I have set up in my main controller. The array is populated by an AJAX request that fires when a user to administer is selected from a dropdown.
I want to notify the user if they have unsaved changes before they navigate away or change the user they are wanting to administer. So, I set up a second array called originalPermissions that is set to the same data as the $scopes.permission array, like so:
$http.post(ajaxurl, user_data)
.success(function(data) {
// Get the permissions model from the server and store to the $scope
console.log('Setting');
$scope.permissions = data;
$scope.origPermissions = data;
...}
Then, each of the checkboxes have an ng-click="updatePermission(data.path)" function call. It likes like this:
$scope.updatePermission = function (path) {
//get the position of the target path in the array
var position = $scope.permissions.indexOf(path);
//if it doesn't exist, its position will be -1
if(position == -1){
// Push the path into the Array if it doesn't exist
$scope.permissions.push(path);
} else {
// Remove the permission from the array if it was already there
$scope.permissions.splice(position, 1);
}
console.log('Perms: '+$scope.permissions);
console.log('OldPerms: '+$scope.origPermissions);
}
Even though I am only performing pushes on the $scope.permissions array, the $scope.origPermissions array is getting updated as well (the console.logs are outputting identical things). This is not desirable, because I want to see if the new stuff in permissions is different from what we have in origPermissions; if so, I want to fire a confirmation box saying "You have unsaved changes..." etc.
That said, I know watchCollection() exists in angular, but as far as I understand, watchCollection notifies you whenever the permissions array changes, but there's no way to tell if it is the same as it was when originally set.
So: why would origPermissions get updated along with scope? Is it because I'm setting each array to the same value, so Angular is assuming it's essentially the same thing? Is there a better way to do this that's more in keeping with the "Angular way"?
$scope.permissions = data;
$scope.origPermissions = data;
data "points" to the same array.
You can use slice to return a new array
$scope.permissions = data.slice();
$scope.origPermissions = data;
I have an object in an array
var
sidelist = [
{
name:"MURICA",
types:[...]
}
];
I have a box that displays the object's name. Then I have a text field and a button. On button press the object's name gets set to text field value. But I don't know how to make the name in the box change accordingly.
As I understand putting the object in a session variable is not an option since I will not be able to modify properties of objects inside of it without resetting the whole session var. I tried it and failed.
html
<template name="asdf">
{{#with object}}
<div>{{name}}</div>
{{/with}}
</template>
js
Template.asdf.object = function() {
return Objects.findOne(...);
};
EDIT
I think I've got your question wrong, sorry. If you have a value in memory that you'd like to change and have the DOM updated, use dependencies:
html
<template name="asdf">
{{property}}
</template>
js
var property;
// Create new dependency object that will manage refreshing property value:
var _dep = new Deps.Dependency;
updateProperty = function(value) {
property = value;
// Whenever you change value of the property, call changed() function:
_dep.changed();
};
Template.asdf.value = function() {
// Within reactive function, call depend() to rerun the function
// each time the value is changed:
_dep.depend();
return value;
};
How about a different and in my opinion simpler solution - using a local collection for your data.
I am not sure exactly why do you keep that sort of data into an array, but if it is because you only need it on the client then you can instead create a local collection and have all the reactivity benefits without writing all that code for making the array reactive. The data stored in a local collection is never sent to the server, so no communication or storage overhead.
You'd do it like that:
Sidelist = new Meteor.Collection(null);
[EDIT] Put the above line in your client-side-only part of the code.
Notice the null parameter. This will give you a collection that is only stored on the client and is a regular Meteor reactive source. Then you go about using it in your code and html just as you would a normal collection.
Hope that helps.