How to update object value on click using behaviorsubject Angular 5? - javascript

Service.ts:
I have create an object in my service.ts file, Now I want to update object values using BehaviorSubject, so I can use this updated object in my different components
private _menuUpdate = {
bankFlag: false,
contactsFlag: false,
educationDataFlag: false,
examFlag: false,
existingRelationShipFlag: false,
nomineeFlag: false,
personalFlag: false,
supportDocsFalg: false,
workExpFlag: false
}
public menuDisableStatus = new BehaviorSubject<Object>(this._menuUpdate);
menuStatus = this.menuDisableStatus.asObservable();
changeStatus(statusObj) {
this.menuDisableStatus.next(statusObj);
}
Now in my components1.ts Example
click(){
this.menuDisableStatus.educationDataFlag = true;
this.mliService.changeStatus(this.menuDisableStatus.educationDataFlag);
}
Now in my components2.ts Example
this.mliService.menuStatus.subscribe((data) => {
this.menuDisableStatus = data;
});
console.log(this.menuDisableStatus);
Here console give me 'true' instead of Update object.

In your component1 you call changeStatus (and in result the "next" of the observable) not to the primary subject but to a property of this subject.
Change it to this.mliService.changeStatus(this.menuDisableStatus); and it should work

Related

Vue2 change object property from method param passing into child props

oi, this one seems so simple but it's giving me a headache.
I have a child component with a property passed down:
<dialog-child requests='requests'/>
the passed prop, is an object obtaining varied booleans. The dialog is v-modeled to in this case,
<dialog v-model='request.deleteItem'>
requests { deleteItem: false, editItem: false, syncItem: false, }
When I click on the delete button, I want to make a request to delete an item, and pull up this dialog component. This works fine if i simply change the bool in the object to true, but I need more control by passing the #click to a method and passing a parameter.
<btn #click='makeRequest(deleteItem)'>Activate Dialog</btn>
so in the method, I need to figure out how to say that the passed deleteItem, is request.deleteItem and then I would make it true.
makeRequest(requested){
//somewhow say
this.requests.requested = true
}
How could I pass in the parameter to take control of the objects property?
I could do a long form of multiple if checks, if requested = '' then make this prop true, but that feels gross.
I also need to pass in a second param, item after I figure this out - so to pass in two params do i just say methodName(param1, param2) and on click method(item1, item2) or do I need to create an object like method({item1, item2})?
To have everything nice and neat :) but:
For that we need option "to emit event on child component" but Vue.js does not work like that. So try this:
<template>
<div>
<dialog-child requests='requests' #resetRequest="resetRequest()"/>
<btn #click='makeRequest("deleteItem")'>Delete</btn>
</div>
</template>
<script>
import DialogChild from 'Dialog.vue'
export default {
components: { "dialog-child" : DialogChild },
data() {
return {
requests: {
makeRequest: false, //New Field
deleteItem: false,
editItem: false,
syncItem: false
}
}
},
methods: {
makeRequest(action) {
//So here you can create new request Object with whatever you want. Use action argument to check what you want to do here...
let newRequests = {
makeRequest: true,
deleteItem: true,
editItem: false,
syncItem: false
}
//Then this newRequest object need to copy to this.requests, this will update request object reference, and trigger "watch" in child component
this.requests = newRequests;
},
resetRequest() {
//Request object is again updated with new reference, but makeRequest is false so it will not trigger action in Dialog Child component
this.requests = {
makeRequest: false, //Now this is false,
deleteItem: false,
editItem: false,
syncItem: false
}
}
}
}
</script>
//And child component should be like this
<template>
<div>
</div>
</template>
<script>
export default {
props: {
requests: { Type: Object }
},
watch: {
requests(newVal) {
if(newVal && newVal.makeRequest) {
this.doStuff()
}
}
},
methods: {
doStuff() {
//So after doing what you want, you need to make event to reset requests
this.$emit('resetRequests');
}
}
}
</script>
i fixed this by changing the param to a string, and removing the request for a second item. Onwards to a item pass in too.

Why local storage not persisting after page refresh

The button text 'completed' should persist after browser refresh based on whether var item is true (after button click). I am not sure what the issue is but I have tried Chrome as well so I don't think it is browser related.
<template>
<button type="button" v-bind:class="order_button_style" #click="on_order_button_click()">
{{ buttonText }}
</button>
</div>
</template>
<script>
export default {
item: '',
data() {
return {
item2: this.item
}
},
methods: {
on_order_button_click() {
this.item2 = true;
localStorage.setItem(this.item2);
}
},
mounted() {
const storedState = localStorage.getItem(this.item2) === 'false';
if (storedState) {
this.item2 = storedState;
}
},
computed: {
buttonText() {
return this.item2 === true ? "Completed" : "Complete";
},
order_button_style() {
return this.item2 === true
? "btn btn-danger"
: "btn btn-primary";
}
}
};
</script>
localStorage.setItem takes 2 params, name and value.
I believe you meant to write the following:
Setting an item in localStorage
localStorage.setItem('item', this.item2)
and retrieving it
localStorage.getItem('item')
A few comments on other parts of your code:
this.item2 === true can be shortened to this.item2 if item2 can never be anything other than a boolean.
You're currently only using the value from localStorage if it's false, which it will never be because you're only ever calling setItem with a value of true
I'm not sure what you're trying to do with the item prop in the top level of the object
Strongly consider using camelCase for your method names. Follow global conventions
UPDATE:
I think this is what you're trying to achieve:
on_order_button_click() { // Should probably rename this to `onOrderButtonClick`, the current method name hurts to look at
this.clickedOrderButton = true;
localStorage.setItem('clickedOrderButton', this.clickedOrderButton);
}
created() {
this.clickedOrderButton = localStorage.getItem('clickedOrderButton') === "true";
}
I've renamed item2 to clickedOrderButton. I have no idea why you'd name that variable item2 based on the code that is shown.
There's also no need to check whether clickedOrderButton is true before assigning it to clickedOrderButton, as it will resolve to false if it's not present (or intentionally set to something other than true) in localStorage.
Lastly, I've replaced mounted by created. As you're not accessing any DOM elements, there's no need to wait until the component is mounted to run that code
UPDATE#2:
If you have several instances of this component, you'll need to set use a different name than clickedOrderButton. You can use a unique identifier per button, which you can pass as a prop from above.
E.g.
props: {
id: { type: String, required: true }
}
...
localStorage.setItem(`clickedOrderButton-${this.id}`, this.clickedOrderButton);
...
localStorage.getItem(`clickedOrderButton-${this.id}`);

Ember pushObjects() not notifying computed property

I'm trying to use ember-light-table and I'm having some troubles on updating my array of objects.
When I use the action updateList(), I can see both arrays changing (adding/removing objects to the list), but the computed property tableModel is not triggered!
I thought pushObjects() would do the trick, but it's not notifying for some reason (it's adding). I also tried to initialize select_people with Ember.A(), although [] should already be an ember array...
My mixin:
// table-testing
import Ember from 'ember';
import Table from 'ember-light-table';
export default Ember.Mixin.create({
table: null,
tableColumns: null,
tableModel: null,
init() {
this._super(...arguments);
let table = new Table(this.get('tableColumns'), this.get('tableModel'), { enableSync: this.get('enableSync') });
this.set('table', table);
}
});
My controller
import Ember from 'ember';
import TableTesting from '../mixins/table-testing';
const { computed } = Ember;
export default Ember.Controller.extend(TableTesting, {
tableColumns: computed(function() {
return [{
label: 'First Name',
valuePath: 'firstName',
width: '50%',
sortable: false,
}, {
label: 'Last Name'
valuePath: 'lastName',
width: '50%'
}]
}),
tableModel: computed('selected_people.#each.firstName', function() {
// THIS MESSAGE ONLY SHOW WHEN VIEW IS RENDERED
// I've tried .[], .#each, .length... none of them worked and I believe #each.firstName would be the most appropriated from what I've read
console.log('computed method not showing',this.get('selected_people'));
return this.get('selected_people');
}),
init() {
this._super(...arguments);
this.set('selected_people',[]);
},
actions: {
updateList(item, moveToList) {
let removeFromList, fromList, toList;
if (moveToList === 'people') {
removeFromList = 'selected_people'
} else if (moveToList === "selected_people") {
removeFromList = 'people';
}
// get the object lists
fromList = this.get(removeFromList);
toList = this.get(moveToList);
// update list ---> HERE I UPDATE USING KOVL METHOD
toList.pushObjects(item);
fromList.removeObjects(item);
console.log('update!',this.get('selected_people'));
}
}
Just make sure tableModel should be accessed/required by the template or in code.
Computed property is lazy, so it will be calculated when you ask for it either inside the code or in a template. otherwise, it will not be called.
First time when we call, it will return result and it will be cached. and subsequent access will get it from cache. Changing any of the dependent properties causes the cache to invalidate so that the computed function runs again on the next access.
Mostlty copied from guides.emberjs

Add a new Key: value pair into every existing array of a object JS, React.js

I'm new to react and learning it at a get go paste. I'm building a small PokemonApp that gets its data through the PokemonAPI and it render's it to the web.
The only data that I'm fetching through the API is the Pokemon name and URL of the Pokemon. The component that fetches the data is called getDataFromAPI and it uses axios (promises) to get it. The data is stored in the pokemoni array and is displayed on the browser. The state shown through the Crome's React Dew Tools is this.
State
pokemoni: Array[20]
0: {...}
name: "metapod"
url: "http://pokeapi.co/api/v2/pokemon/11/"
1: {...}
Now i wont to add a new [{key: value}] pair to all the existing objects that will change from false to true when the user clicks on a Pokemon that they got (it will be a button or something else). The state of the change by the user will be made only once (from false to true).
State
pokemoni: Array[20]
0: {...}
name: "metapod"
url: "http://pokeapi.co/api/v2/pokemon/11/"
havePokemon: "false"
1: {...}
The logic i came to was using .map() to add a new [{key: value}] pair to all the existing objects. And doesn't work. Because i don't understand the problem. The function is located inside the getDataFromAPI component and it is called updatePokemon
var PokedexApp = React.createClass({
componentDidMount: function(){
this.getDataFromAPI();
},
getDataFromAPI: function(){
var that = this;
PokemonAPI.getPokemonList().then(function (temp) {
that.setState({
pokemoni: temp,
isLoading: false
});
}, function (e) {
that.setState({
isLoading: true
});
});
//This function should update the array with a new key: value pair with the name havePokemon
var updatePokemon = this.state.pokemoni.map(function(myPokemon){
myPokemon.havePokemon= "false";
return myPokemon;
});
this.setState({pokemoni: updatePokemon});
},
componentWillUnmount: function() {
this.getDataFromAPI.abort();
},
getInitialState: function() {
return{
showMyPokemon: false,
searchPokemon: '',
pokemoni: [],
isLoading: false
};
},
render: function(){
var {pokemoni, showMyPokemon, searchPokemon} = this.state;
var filteredPokemoni = PokemonLocalStorageAPI.filterPokemone(pokemoni, showMyPokemon, searchPokemon);
return (
<div>
<h1 className="text-center page-title">PokedexApp</h1>
<PokedexAppSearch onSearch={this.handleSearch} />
<PokedexAppLista pokemoni={filteredPokemoni} onToggle={this.handleToggle}/>
</div>
)
}
});
module.exports = PokedexApp;
It does not work and i don't understand why. Ty in advance if u have the time to check my problem.

Emberjs - Controller always gets default value from 'needs' controller

I have a situation where I have an application controller that 'needs' to access a property from another controller, like this:
App.ApplicationController = Ember.Controller.extend({
needs: ['sort'],
actions: {
appClicked: function () {
console.log('controllers.sort.isMenuExpanded');
}
}
});
App.SortController = Ember.Controller.extend({
isMenuExpanded: false,
actions: {
menuClicked: function () {
this.toggleProperty('isMenuExpanded');
}
}
})
As expected, the ApplicationController's appClicked function correctly logs 'false' the first time it is run. However, it continues logging false (the default value set in the SortController) even after the isMenuExpanded property has been changed to 'true' by the SortController.
This may have something to do with the way JavaScript passes values. I think objects are passed by reference, and sure enough, if I change the isMenuExpanded property to:
isMenuExpanded: { expanded: false }
and change the toggle to:
this.toggleProperty('isMenuExpanded.expanded');
the action in the ApplicationController correctly prints the isMenuExpanded.expanded value to the console every time it's updated.
Thanks in advance for your time and expertise!
Try setting it as a computed property.
App.ApplicationController = Ember.Controller.extend({
needs: ['sort'],
isMenuExpanded: Ember.computed.alias('controllers.sort.isMenuExpanded'),
actions: {
appClicked: function () {
console.log(this.get('isMenuExpanded'));
}
}
});
App.SortController = Ember.Controller.extend({
isMenuExpanded: false,
actions: {
menuClicked: function () {
this.toggleProperty('isMenuExpanded');
}
}
})

Categories